UX redesign, some grooming.
This commit is contained in:
parent
a928449c90
commit
f096fcec4f
11
Makefile
11
Makefile
@ -18,7 +18,7 @@ main.js: main.bundle.js
|
|||||||
$(Q)npx babel --minified main.bundle.js -o main.js
|
$(Q)npx babel --minified main.bundle.js -o main.js
|
||||||
|
|
||||||
|
|
||||||
main.bundle.js: client/index.ls client/authd.ls client/authws.ls client/bulma.ls client/card.ls client/modal.ls client/navbar.ls client/project-creation-modal.ls client/project.ls client/task-creation-modal.ls client/task.ls client/task-removal-modal.ls client/todowebsocket.ls client/validation-modal.ls
|
main.bundle.js: client/index.ls client/authws.ls client/bulma.ls client/card.ls client/column-edit-modal.ls client/font-awesome.ls client/modal.ls client/navbar.ls client/project-creation-modal.ls client/project.ls client/task-creation-modal.ls client/task.ls client/task-removal-modal.ls client/todowebsocket.ls client/validation-modal.ls
|
||||||
@echo '[01;32m BUN > [01;37mmain.bundle.js[00m'
|
@echo '[01;32m BUN > [01;37mmain.bundle.js[00m'
|
||||||
$(Q)npx browserify -t browserify-livescript client/index.ls -o main.bundle.js
|
$(Q)npx browserify -t browserify-livescript client/index.ls -o main.bundle.js
|
||||||
|
|
||||||
@ -96,10 +96,11 @@ $(PACKAGE)-$(VERSION).tar.gz: distdir
|
|||||||
$(Q)tar czf $(PACKAGE)-$(VERSION).tar.gz \
|
$(Q)tar czf $(PACKAGE)-$(VERSION).tar.gz \
|
||||||
$(PACKAGE)-$(VERSION)/client/index.ls \
|
$(PACKAGE)-$(VERSION)/client/index.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/style.sass \
|
$(PACKAGE)-$(VERSION)/client/style.sass \
|
||||||
$(PACKAGE)-$(VERSION)/client/authd.ls \
|
|
||||||
$(PACKAGE)-$(VERSION)/client/authws.ls \
|
$(PACKAGE)-$(VERSION)/client/authws.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/bulma.ls \
|
$(PACKAGE)-$(VERSION)/client/bulma.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/card.ls \
|
$(PACKAGE)-$(VERSION)/client/card.ls \
|
||||||
|
$(PACKAGE)-$(VERSION)/client/column-edit-modal.ls \
|
||||||
|
$(PACKAGE)-$(VERSION)/client/font-awesome.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/modal.ls \
|
$(PACKAGE)-$(VERSION)/client/modal.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/navbar.ls \
|
$(PACKAGE)-$(VERSION)/client/navbar.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/project-creation-modal.ls \
|
$(PACKAGE)-$(VERSION)/client/project-creation-modal.ls \
|
||||||
@ -116,10 +117,11 @@ $(PACKAGE)-$(VERSION).tar.xz: distdir
|
|||||||
$(Q)tar cJf $(PACKAGE)-$(VERSION).tar.xz \
|
$(Q)tar cJf $(PACKAGE)-$(VERSION).tar.xz \
|
||||||
$(PACKAGE)-$(VERSION)/client/index.ls \
|
$(PACKAGE)-$(VERSION)/client/index.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/style.sass \
|
$(PACKAGE)-$(VERSION)/client/style.sass \
|
||||||
$(PACKAGE)-$(VERSION)/client/authd.ls \
|
|
||||||
$(PACKAGE)-$(VERSION)/client/authws.ls \
|
$(PACKAGE)-$(VERSION)/client/authws.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/bulma.ls \
|
$(PACKAGE)-$(VERSION)/client/bulma.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/card.ls \
|
$(PACKAGE)-$(VERSION)/client/card.ls \
|
||||||
|
$(PACKAGE)-$(VERSION)/client/column-edit-modal.ls \
|
||||||
|
$(PACKAGE)-$(VERSION)/client/font-awesome.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/modal.ls \
|
$(PACKAGE)-$(VERSION)/client/modal.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/navbar.ls \
|
$(PACKAGE)-$(VERSION)/client/navbar.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/project-creation-modal.ls \
|
$(PACKAGE)-$(VERSION)/client/project-creation-modal.ls \
|
||||||
@ -136,10 +138,11 @@ $(PACKAGE)-$(VERSION).tar.bz2: distdir
|
|||||||
$(Q)tar cjf $(PACKAGE)-$(VERSION).tar.bz2 \
|
$(Q)tar cjf $(PACKAGE)-$(VERSION).tar.bz2 \
|
||||||
$(PACKAGE)-$(VERSION)/client/index.ls \
|
$(PACKAGE)-$(VERSION)/client/index.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/style.sass \
|
$(PACKAGE)-$(VERSION)/client/style.sass \
|
||||||
$(PACKAGE)-$(VERSION)/client/authd.ls \
|
|
||||||
$(PACKAGE)-$(VERSION)/client/authws.ls \
|
$(PACKAGE)-$(VERSION)/client/authws.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/bulma.ls \
|
$(PACKAGE)-$(VERSION)/client/bulma.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/card.ls \
|
$(PACKAGE)-$(VERSION)/client/card.ls \
|
||||||
|
$(PACKAGE)-$(VERSION)/client/column-edit-modal.ls \
|
||||||
|
$(PACKAGE)-$(VERSION)/client/font-awesome.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/modal.ls \
|
$(PACKAGE)-$(VERSION)/client/modal.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/navbar.ls \
|
$(PACKAGE)-$(VERSION)/client/navbar.ls \
|
||||||
$(PACKAGE)-$(VERSION)/client/project-creation-modal.ls \
|
$(PACKAGE)-$(VERSION)/client/project-creation-modal.ls \
|
||||||
|
177
client/authd.ls
177
client/authd.ls
@ -1,177 +0,0 @@
|
|||||||
bulma = require "./bulma.ls"
|
|
||||||
h = require 'maquette' .h
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
create-socket: (socket-url) ->
|
|
||||||
self = {}
|
|
||||||
|
|
||||||
self.token = ""
|
|
||||||
|
|
||||||
request-types = {
|
|
||||||
"get-token": 0
|
|
||||||
"add-user": 1
|
|
||||||
"get-user": 2
|
|
||||||
"get-user-by-credentials": 3
|
|
||||||
"mod-user": 4
|
|
||||||
|
|
||||||
# TODO: code these messages
|
|
||||||
"register": 5
|
|
||||||
"get-extra": 6
|
|
||||||
"set-extra": 7
|
|
||||||
"update-password": 8
|
|
||||||
|
|
||||||
"list-users": 9
|
|
||||||
"set-permissions": 10
|
|
||||||
}
|
|
||||||
|
|
||||||
response-types = {
|
|
||||||
"error": 0
|
|
||||||
"token": 1
|
|
||||||
"user": 2
|
|
||||||
"user-added": 3
|
|
||||||
"user-edited": 4
|
|
||||||
"extra": 5
|
|
||||||
"extra-updated": 6
|
|
||||||
"users-list": 7
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO: naming convention
|
|
||||||
# users can record functions to run on events
|
|
||||||
self.user-on-socket-error = []
|
|
||||||
self.user-on-socket-close = []
|
|
||||||
|
|
||||||
self.callbacks = {}
|
|
||||||
for key, value of response-types
|
|
||||||
self.callbacks[value] = []
|
|
||||||
|
|
||||||
# self.user-on-message = []
|
|
||||||
|
|
||||||
self.add-event-listener = (type, callback) ->
|
|
||||||
type = response-types[type]
|
|
||||||
|
|
||||||
self.callbacks[type] ++= [callback]
|
|
||||||
|
|
||||||
self.open-socket = ->
|
|
||||||
console.log "Opening socket to #{socket-url}"
|
|
||||||
self.socket := new WebSocket socket-url
|
|
||||||
|
|
||||||
self.socket.onerror = (event) ->
|
|
||||||
for f in self.user-on-socket-error
|
|
||||||
f event
|
|
||||||
self.socket.close!
|
|
||||||
|
|
||||||
self.socket.onclose = (event) ->
|
|
||||||
for f in self.user-on-socket-close
|
|
||||||
f event
|
|
||||||
|
|
||||||
self.socket.onmessage = (event) ->
|
|
||||||
message = JSON.parse(event.data)
|
|
||||||
|
|
||||||
for f in self.callbacks[message.mtype]
|
|
||||||
f JSON.parse(message.payload)
|
|
||||||
|
|
||||||
self.reopen = ->
|
|
||||||
self.socket.close!
|
|
||||||
self.open-socket!
|
|
||||||
|
|
||||||
self.open-socket!
|
|
||||||
|
|
||||||
self.send = (type, opts) ->
|
|
||||||
self.socket.send JSON.stringify { mtype: type, payload: opts }
|
|
||||||
|
|
||||||
self.get-token = (login, password) ->
|
|
||||||
self.send request-types[\get-token], JSON.stringify {
|
|
||||||
login: login
|
|
||||||
password: password
|
|
||||||
}
|
|
||||||
|
|
||||||
self.get-user-by-credentials = (login, password) ->
|
|
||||||
self.send request-types[\get-user-by-credentials], JSON.stringify {
|
|
||||||
login: login
|
|
||||||
password: password
|
|
||||||
}
|
|
||||||
|
|
||||||
self.login = (login, password) ->
|
|
||||||
self.get-token login, password
|
|
||||||
self.get-user-by-credentials login, password
|
|
||||||
|
|
||||||
|
|
||||||
self.get-user = (uid) ->
|
|
||||||
self.send request-types[\get-user], JSON.stringify {
|
|
||||||
uid: uid
|
|
||||||
}
|
|
||||||
|
|
||||||
self.list-users = ->
|
|
||||||
self.send request-types[\list-users], JSON.stringify {
|
|
||||||
token: self.token
|
|
||||||
# FIXME: this will be removed once the authd program will accept
|
|
||||||
# any list-users requests from any user
|
|
||||||
# which is the only logical choice since any user can create projects and assign people to it
|
|
||||||
key: "nico-nico-nii"
|
|
||||||
}
|
|
||||||
|
|
||||||
self.set-permissions = (list-id, user-id, permission) ->
|
|
||||||
self.send request-types[\set-permissions], JSON.stringify {
|
|
||||||
token: self.token
|
|
||||||
list: list-id
|
|
||||||
uid: user-id
|
|
||||||
permission: permission
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO: authd overhaul
|
|
||||||
#self.add-user = (login, password) ->
|
|
||||||
# self.send request-types[\add-user], JSON.stringify {
|
|
||||||
# login: login
|
|
||||||
# password: password
|
|
||||||
# }
|
|
||||||
|
|
||||||
# TODO: authd overhaul
|
|
||||||
#self.mod-user = (uid) ->
|
|
||||||
# self.send request-types[\mod-user], JSON.stringify {
|
|
||||||
# uid: uid
|
|
||||||
# }
|
|
||||||
|
|
||||||
self
|
|
||||||
|
|
||||||
login-page: (model) ->
|
|
||||||
# XXX: container = marge
|
|
||||||
# XXX: box = dessiner un contour
|
|
||||||
h \div.container [
|
|
||||||
h \div.box [
|
|
||||||
if model.login-error
|
|
||||||
h \div.notification.is-danger [
|
|
||||||
model.login-error
|
|
||||||
]
|
|
||||||
h \form [
|
|
||||||
bulma.field [
|
|
||||||
bulma.label "Login"
|
|
||||||
bulma.input {
|
|
||||||
oninput: (e) ->
|
|
||||||
model.login = e.target.value
|
|
||||||
name: \login
|
|
||||||
id: \login-input
|
|
||||||
}
|
|
||||||
]
|
|
||||||
bulma.field [
|
|
||||||
bulma.label "Password"
|
|
||||||
bulma.input {
|
|
||||||
oninput: (e) ->
|
|
||||||
model.password = e.target.value
|
|
||||||
name: \password
|
|
||||||
type: \password
|
|
||||||
id: \password-input
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
h \button.button.is-fullwidth.is-primary {
|
|
||||||
onclick: (e) ->
|
|
||||||
# not to refresh the page since it's a form button
|
|
||||||
e.prevent-default!
|
|
||||||
|
|
||||||
model.authd-ws.get-token model.login, model.password
|
|
||||||
} [ "Connexion" ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
136
client/authws.ls
Normal file
136
client/authws.ls
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
bulma = require "./bulma.ls"
|
||||||
|
h = require 'maquette' .h
|
||||||
|
|
||||||
|
AuthWS = (socket-url) ->
|
||||||
|
self = {}
|
||||||
|
|
||||||
|
request-types = {
|
||||||
|
"get-token": 0
|
||||||
|
"add-user": 1
|
||||||
|
"get-user": 2
|
||||||
|
"get-user-by-credentials": 3
|
||||||
|
"mod-user": 4
|
||||||
|
"register": 5
|
||||||
|
"update-password": 6
|
||||||
|
"list-users": 7
|
||||||
|
"check-permission": 8
|
||||||
|
"set-permission": 9
|
||||||
|
}
|
||||||
|
|
||||||
|
response-types = {
|
||||||
|
"error": 0
|
||||||
|
"token": 1
|
||||||
|
"user": 2
|
||||||
|
"user-added": 3
|
||||||
|
"user-edited": 4
|
||||||
|
"users-list": 5
|
||||||
|
"permission-check": 6
|
||||||
|
"permission-set": 7
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: naming convention
|
||||||
|
# users can record functions to run on events
|
||||||
|
self.user-on-socket-error = []
|
||||||
|
self.user-on-socket-close = []
|
||||||
|
|
||||||
|
self.callbacks = {}
|
||||||
|
for key, value of response-types
|
||||||
|
self.callbacks[value] = []
|
||||||
|
|
||||||
|
self.add-event-listener = (type, callback) ->
|
||||||
|
type = response-types[type]
|
||||||
|
|
||||||
|
self.callbacks[type] ++= [callback]
|
||||||
|
|
||||||
|
self.open-socket = ->
|
||||||
|
self.socket := new WebSocket socket-url
|
||||||
|
|
||||||
|
self.socket.onerror = (event) ->
|
||||||
|
for f in self.user-on-socket-error
|
||||||
|
f event
|
||||||
|
self.socket.close!
|
||||||
|
|
||||||
|
self.socket.onclose = (event) ->
|
||||||
|
for f in self.user-on-socket-close
|
||||||
|
f event
|
||||||
|
|
||||||
|
self.socket.onmessage = (event) ->
|
||||||
|
message = JSON.parse(event.data)
|
||||||
|
|
||||||
|
for f in self.callbacks[message.mtype]
|
||||||
|
f JSON.parse(message.payload)
|
||||||
|
|
||||||
|
self.reopen = ->
|
||||||
|
self.socket.close!
|
||||||
|
self.open-socket!
|
||||||
|
|
||||||
|
self.open-socket!
|
||||||
|
|
||||||
|
self.send = (type, opts) ->
|
||||||
|
self.socket.send JSON.stringify { mtype: type, payload: opts }
|
||||||
|
|
||||||
|
self.get-token = (login, password) ->
|
||||||
|
self.send request-types[\get-token], JSON.stringify {
|
||||||
|
login: login
|
||||||
|
password: password
|
||||||
|
}
|
||||||
|
|
||||||
|
self.get-user-by-credentials = (login, password) ->
|
||||||
|
self.send request-types[\get-user-by-credentials], JSON.stringify {
|
||||||
|
login: login
|
||||||
|
password: password
|
||||||
|
}
|
||||||
|
|
||||||
|
self.login = (login, password) ->
|
||||||
|
self.get-token login, password
|
||||||
|
self.get-user-by-credentials login, password
|
||||||
|
|
||||||
|
|
||||||
|
self.get-user = (uid) ->
|
||||||
|
self.send request-types[\get-user], JSON.stringify {
|
||||||
|
uid: uid
|
||||||
|
}
|
||||||
|
|
||||||
|
self.register = (login, password) ->
|
||||||
|
self.send request-types[\register], JSON.stringify {
|
||||||
|
login: login
|
||||||
|
password: password
|
||||||
|
}
|
||||||
|
|
||||||
|
self.get-extra = (token, name) ->
|
||||||
|
console.warn "get-extra: deprecated"
|
||||||
|
|
||||||
|
self.set-extra = (token, name, extra) ->
|
||||||
|
console.warn "set-extra: deprecated"
|
||||||
|
|
||||||
|
self.update-password = (login, old-password, new-password) ->
|
||||||
|
self.send request-types[\update-password], JSON.stringify {
|
||||||
|
login: login
|
||||||
|
old_password: old-password
|
||||||
|
new_password: new-password
|
||||||
|
}
|
||||||
|
|
||||||
|
self.list-users = (token) ->
|
||||||
|
console.warn "list-users: unstable API"
|
||||||
|
|
||||||
|
self.send request-types[\list-users], JSON.stringify {
|
||||||
|
token: token
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: authd overhaul required
|
||||||
|
#self.add-user = (login, password) ->
|
||||||
|
# self.send request-types[\add-user], JSON.stringify {
|
||||||
|
# login: login
|
||||||
|
# password: password
|
||||||
|
# }
|
||||||
|
|
||||||
|
# TODO: authd overhaul required
|
||||||
|
#self.mod-user = (uid) ->
|
||||||
|
# self.send request-types[\mod-user], JSON.stringify {
|
||||||
|
# uid: uid
|
||||||
|
# }
|
||||||
|
|
||||||
|
self
|
||||||
|
|
||||||
|
module.exports = AuthWS
|
||||||
|
|
44
client/column-edit-modal.ls
Normal file
44
client/column-edit-modal.ls
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{h} = require "maquette"
|
||||||
|
|
||||||
|
{field, control, input, label} = require "./bulma.ls"
|
||||||
|
|
||||||
|
Modal = require "./modal.ls"
|
||||||
|
|
||||||
|
deep-copy = (object) ->
|
||||||
|
JSON.parse JSON.stringify object
|
||||||
|
|
||||||
|
ColumnEditModal = (project, column, args) ->
|
||||||
|
self = {
|
||||||
|
column: deep-copy column
|
||||||
|
|
||||||
|
on-validation: args.on-validation || (column) ->
|
||||||
|
}
|
||||||
|
|
||||||
|
modal = Modal {
|
||||||
|
+visible
|
||||||
|
|
||||||
|
content: [
|
||||||
|
field [
|
||||||
|
label "Column title"
|
||||||
|
|
||||||
|
control [
|
||||||
|
input {
|
||||||
|
value: self.column.title
|
||||||
|
oninput: (e) ->
|
||||||
|
self.column.title = e.target.value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
on-validation: ->
|
||||||
|
self.on-validation self.column
|
||||||
|
}
|
||||||
|
|
||||||
|
self.render = ->
|
||||||
|
modal.render!
|
||||||
|
|
||||||
|
self
|
||||||
|
|
||||||
|
module.exports = ColumnEditModal
|
||||||
|
|
13
client/font-awesome.ls
Normal file
13
client/font-awesome.ls
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{h} = require "maquette"
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
icon: (selector, icon) ->
|
||||||
|
unless icon
|
||||||
|
icon = selector
|
||||||
|
selector = ""
|
||||||
|
|
||||||
|
h (\span.icon + selector), [
|
||||||
|
h "span.fas.fa-#{icon}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,16 +1,15 @@
|
|||||||
|
|
||||||
maquette = require "maquette"
|
maquette = require "maquette"
|
||||||
nmd = require "nano-markdown"
|
nmd = require "nano-markdown"
|
||||||
authd = require "./authd.ls"
|
|
||||||
LoginForm = require "../lib/authd/client/login-form.ls"
|
LoginForm = require "../lib/authd/client/login-form.ls"
|
||||||
todows = require "./todowebsocket.ls"
|
todows = require "./todowebsocket.ls"
|
||||||
|
AuthWS = require "./authws.ls"
|
||||||
bulma = require "./bulma.ls"
|
bulma = require "./bulma.ls"
|
||||||
Task = require "./task.ls"
|
Task = require "./task.ls"
|
||||||
Project = require "./project.ls"
|
Project = require "./project.ls"
|
||||||
Modal = require "./modal.ls"
|
Modal = require "./modal.ls"
|
||||||
Navbar = require "./navbar.ls"
|
Navbar = require "./navbar.ls"
|
||||||
# ValidationModal = require "./validation-modal.ls"
|
# ValidationModal = require "./validation-modal.ls"
|
||||||
UUID = require "uuid/v4"
|
|
||||||
|
|
||||||
{create-projector, h} = maquette
|
{create-projector, h} = maquette
|
||||||
projector = create-projector!
|
projector = create-projector!
|
||||||
@ -58,7 +57,7 @@ console.log "todod url: " + model.todod-url
|
|||||||
# network configuration
|
# network configuration
|
||||||
#
|
#
|
||||||
|
|
||||||
model.authd-ws = authd.create-socket model.authd-url
|
model.authd-ws = AuthWS model.authd-url
|
||||||
model.todod-ws = todows.create-socket model.todod-url
|
model.todod-ws = todows.create-socket model.todod-url
|
||||||
|
|
||||||
|
|
||||||
@ -71,9 +70,13 @@ model.todod-ws = todows.create-socket model.todod-url
|
|||||||
authd-on-websocket-error = (event) ->
|
authd-on-websocket-error = (event) ->
|
||||||
console.log "WebSocket error.", event
|
console.log "WebSocket error.", event
|
||||||
model.current-view := "network-error"
|
model.current-view := "network-error"
|
||||||
|
model.last-network-error := event
|
||||||
projector.schedule-render!
|
projector.schedule-render!
|
||||||
|
|
||||||
authd-on-websocket-close = (event) ->
|
authd-on-websocket-close = (event) ->
|
||||||
|
if model.current-view == "network-error"
|
||||||
|
return
|
||||||
|
|
||||||
model.current-view := "login"
|
model.current-view := "login"
|
||||||
console.log "WebSocket has been closed.", event
|
console.log "WebSocket has been closed.", event
|
||||||
# model.todod-ws.reopen!
|
# model.todod-ws.reopen!
|
||||||
@ -122,9 +125,13 @@ model.authd-ws.add-event-listener \users-list, (message) ->
|
|||||||
on-websocket-error = (event) ->
|
on-websocket-error = (event) ->
|
||||||
console.log "WebSocket error.", event
|
console.log "WebSocket error.", event
|
||||||
model.current-view := "network-error"
|
model.current-view := "network-error"
|
||||||
|
model.last-network-error := event
|
||||||
projector.schedule-render!
|
projector.schedule-render!
|
||||||
|
|
||||||
on-websocket-close = (event) ->
|
on-websocket-close = (event) ->
|
||||||
|
if model.current-view == "network-error"
|
||||||
|
return
|
||||||
|
|
||||||
model.current-view := "login"
|
model.current-view := "login"
|
||||||
console.log "WebSocket has been closed.", event
|
console.log "WebSocket has been closed.", event
|
||||||
# model.todod-ws.reopen!
|
# model.todod-ws.reopen!
|
||||||
@ -136,7 +143,7 @@ model.todod-ws.user-on-socket-error ++= [ on-websocket-error ]
|
|||||||
model.todod-ws.user-on-socket-close ++= [ on-websocket-close ]
|
model.todod-ws.user-on-socket-close ++= [ on-websocket-close ]
|
||||||
|
|
||||||
model.todod-ws.add-event-listener \lists-list, (message) ->
|
model.todod-ws.add-event-listener \lists-list, (message) ->
|
||||||
console.log "Project list received", message
|
console.log "Projects list received", message
|
||||||
|
|
||||||
model.project-list := message.lists.map (x) ->
|
model.project-list := message.lists.map (x) ->
|
||||||
old-project = model.project-list.find((.id == x.id))
|
old-project = model.project-list.find((.id == x.id))
|
||||||
@ -192,7 +199,7 @@ model.todod-ws.add-event-listener \tasks, (message) ->
|
|||||||
project = model.project-list.find((.id == message.list))
|
project = model.project-list.find((.id == message.list))
|
||||||
project.tasks := message.tasks.map (e) -> Task e, project, model.todod-ws
|
project.tasks := message.tasks.map (e) -> Task e, project, model.todod-ws
|
||||||
|
|
||||||
if model.viewed-project.id == project.id
|
if model.viewed-project && model.viewed-project.id == project.id
|
||||||
model.viewed-project := project
|
model.viewed-project := project
|
||||||
|
|
||||||
projector.schedule-render!
|
projector.schedule-render!
|
||||||
@ -202,7 +209,7 @@ model.todod-ws.add-event-listener \task-created, (message) ->
|
|||||||
|
|
||||||
task = message.task
|
task = message.task
|
||||||
list = model.project-list.find((.id == task.list))
|
list = model.project-list.find((.id == task.list))
|
||||||
if list.id == model.viewed-project.id
|
if model.viewed-project && list.id == model.viewed-project.id
|
||||||
model.viewed-project := list
|
model.viewed-project := list
|
||||||
|
|
||||||
if list
|
if list
|
||||||
@ -249,12 +256,6 @@ render-project-list = ->
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
Column = (title) ->
|
|
||||||
{
|
|
||||||
title: title
|
|
||||||
id: UUID! # TODO FIXME XXX
|
|
||||||
}
|
|
||||||
|
|
||||||
render-project = (project) ->
|
render-project = (project) ->
|
||||||
if project
|
if project
|
||||||
project.render!
|
project.render!
|
||||||
@ -266,6 +267,10 @@ render-project = (project) ->
|
|||||||
model.login-form = LoginForm {
|
model.login-form = LoginForm {
|
||||||
authws-url: model.authd-url
|
authws-url: model.authd-url
|
||||||
on-login: (user, token) ->
|
on-login: (user, token) ->
|
||||||
|
# FIXME: May double-login if the user clicks the “login” button too much.
|
||||||
|
if model.current-view != "login"
|
||||||
|
return
|
||||||
|
|
||||||
model.current-view := "project-list"
|
model.current-view := "project-list"
|
||||||
model.authd-ws.token := token
|
model.authd-ws.token := token
|
||||||
model.todod-ws.token := token
|
model.todod-ws.token := token
|
||||||
@ -295,6 +300,19 @@ render-body = ->
|
|||||||
render-project-list!
|
render-project-list!
|
||||||
when "project"
|
when "project"
|
||||||
render-project model.viewed-project
|
render-project model.viewed-project
|
||||||
|
when "network-error"
|
||||||
|
h \div.container [
|
||||||
|
h \div.notification.is-danger [
|
||||||
|
h \div.title.is-2 [ "Socket error!" ]
|
||||||
|
|
||||||
|
h \div.content [
|
||||||
|
h \p [ "We’re very sorry, but something got very wrong between here and the backend." ]
|
||||||
|
h \p [ "Please check your network connection and refresh the page." ]
|
||||||
|
|
||||||
|
h \p.small [ "The error happened on " + model.last-network-error.explicit-original-target.url ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
else
|
else
|
||||||
h \div.notification.is-error [
|
h \div.notification.is-error [
|
||||||
|
@ -53,7 +53,7 @@ Modal = (args, caller) ->
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
h \button.button.modal-close {
|
h \a.modal-close {
|
||||||
aria-label: "close"
|
aria-label: "close"
|
||||||
onclick: ->
|
onclick: ->
|
||||||
self.visible := false
|
self.visible := false
|
||||||
|
@ -1,23 +1,18 @@
|
|||||||
{h} = require "maquette"
|
{h} = require "maquette"
|
||||||
|
|
||||||
{button, field, control} = require "./bulma.ls"
|
{button, field, control} = require "./bulma.ls"
|
||||||
|
{icon} = require "./font-awesome.ls"
|
||||||
|
|
||||||
render-new-project-button = (model) ->
|
Modal = require "./modal.ls"
|
||||||
h \div.button.is-success.is-medium.is-outlined {
|
UUID = require "uuid/v4"
|
||||||
onclick: ->
|
|
||||||
model.todod-ws.add-list "New project", {
|
|
||||||
extra_properties: {
|
|
||||||
columns: [
|
|
||||||
Column "Unassigned"
|
|
||||||
Column "Work in progress"
|
|
||||||
Column "To be checked"
|
|
||||||
Column "Being checked"
|
|
||||||
Column "Done"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} [ "New project!" ]
|
|
||||||
|
|
||||||
|
ProjectCreationModal = require "./project-creation-modal.ls"
|
||||||
|
|
||||||
|
Column = (title) ->
|
||||||
|
{
|
||||||
|
title: title
|
||||||
|
id: UUID! # TODO FIXME XXX
|
||||||
|
}
|
||||||
|
|
||||||
Navbar = ->
|
Navbar = ->
|
||||||
self = {}
|
self = {}
|
||||||
@ -45,19 +40,31 @@ Navbar = ->
|
|||||||
if model.current-view != "login"
|
if model.current-view != "login"
|
||||||
h \div.navbar-end [
|
h \div.navbar-end [
|
||||||
if model.current-view == "project-list"
|
if model.current-view == "project-list"
|
||||||
h \div.navbar-item {key: "new project"} [
|
h \a.navbar-item.has-text-success {
|
||||||
render-new-project-button model
|
key: \new-project
|
||||||
|
onclick: ->
|
||||||
|
model.modal := ProjectCreationModal {
|
||||||
|
on-validation: (project) ->
|
||||||
|
model.todod-ws.add-list project.title, project
|
||||||
|
}
|
||||||
|
} [
|
||||||
|
h \span [ "New project" ]
|
||||||
|
|
||||||
|
icon \plus
|
||||||
]
|
]
|
||||||
else if model.current-view == "project" && model.viewed-project
|
else if model.current-view == "project" && model.viewed-project
|
||||||
model.viewed-project.right-nav-render!
|
model.viewed-project.right-nav-render!
|
||||||
|
|
||||||
h \div.navbar-item {key: "logout"} [
|
h \a.navbar-item {
|
||||||
h \a.button.is-medium.is-outlined {
|
key: "logout"
|
||||||
onclick: ->
|
onclick: ->
|
||||||
model.current-view := "login"
|
model.current-view := "login"
|
||||||
# TODO: remove anything related to the old session on the client
|
# TODO: remove anything related to the old session on the client
|
||||||
model.todod-ws.reopen!
|
model.todod-ws.reopen!
|
||||||
} [ "Logout" ]
|
} [
|
||||||
|
h \span [ "Logout" ]
|
||||||
|
|
||||||
|
icon \sign-out-alt
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
@ -6,216 +6,155 @@ bulma = require "./bulma.ls"
|
|||||||
|
|
||||||
{field, control, label, button, tag, input, select} = bulma
|
{field, control, label, button, tag, input, select} = bulma
|
||||||
|
|
||||||
col-to-lines = (column, self) ->
|
deep-copy = (object) ->
|
||||||
field \.has-addons {
|
JSON.parse JSON.stringify object
|
||||||
key: "column.#{column.id}"
|
|
||||||
} [
|
|
||||||
control \.is-expanded [
|
|
||||||
input {
|
|
||||||
key: "input" + column.id
|
|
||||||
value: column.title
|
|
||||||
oninput: (e) ->
|
|
||||||
self.extra_properties.columns.find((.id == column.id)).title := e.target.value
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
control [
|
const PERMISSION_LEVELS = ["admin", "edit", "read"]
|
||||||
button \.is-danger.is-outlined {
|
|
||||||
key: "button" + column.id
|
|
||||||
onclick: ->
|
|
||||||
self.extra_properties.columns := self.extra_properties.columns.filter((.id != column.id))
|
|
||||||
} [ "DELETE" ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
user-form-selection = (self, user) ->
|
remove-permission = (project, uid) ->
|
||||||
h \option {
|
for key, value of project.permissions
|
||||||
value: user.uid
|
project.permissions[key] := value.filter (!= uid)
|
||||||
} [ user.login ]
|
|
||||||
|
|
||||||
permission-groups =
|
add-permission = (project, uid, perm) ->
|
||||||
"read"
|
project.permissions[perm].push uid
|
||||||
"post"
|
|
||||||
"edit"
|
|
||||||
"admin"
|
|
||||||
|
|
||||||
permissions-add = (self, permission, user-id) ->
|
|
||||||
perm-list = self.permissions[permission]
|
|
||||||
if perm-list
|
|
||||||
is-already-there = perm-list.find (e) -> (""+ e) == ("" + user-id)
|
|
||||||
if is-already-there
|
|
||||||
console.log "user #{user-id} already in #{perm-list}"
|
|
||||||
else
|
|
||||||
perm-list ++= [ parseInt(user-id) ]
|
|
||||||
self.permissions[permission] := perm-list
|
|
||||||
# console.log "adding user #{user-id} to #{perm-list[0]}: #{perm-list}"
|
|
||||||
else
|
|
||||||
console.log "Cannot find #{permission} permissions, creating it"
|
|
||||||
self.permissions[permission] := user-id
|
|
||||||
|
|
||||||
permission-to-form-selection = (self, permission) ->
|
|
||||||
h \option {
|
|
||||||
value: permission
|
|
||||||
} [ permission ]
|
|
||||||
|
|
||||||
ProjectCreationModal = (project, todod-ws, users) ->
|
|
||||||
|
|
||||||
# work on a copy of the columns
|
|
||||||
# in case of cancelled modifications, only the copies are changed
|
|
||||||
columns-copy = []
|
|
||||||
for col in project.extra_properties.columns
|
|
||||||
new-col = {}
|
|
||||||
for k,v of col
|
|
||||||
new-col[k] = v
|
|
||||||
columns-copy ++= [ new-col ]
|
|
||||||
|
|
||||||
|
ProjectCreationModal = (args) ->
|
||||||
self = {
|
self = {
|
||||||
title: project.title || ""
|
project: if args.project
|
||||||
permissions: project.permissions || {admin: [], edit: [], post: [], read: []}
|
deep-copy args.project
|
||||||
|
else
|
||||||
|
{}
|
||||||
|
visible: args.visible || true
|
||||||
|
|
||||||
tmp:
|
on-validation: args.on-validation || (project) ->
|
||||||
new-user-permission:
|
|
||||||
id: void
|
|
||||||
permission: permission-groups[0]
|
|
||||||
new-column-input:
|
|
||||||
title: "New column !"
|
|
||||||
users: users || []
|
|
||||||
|
|
||||||
extra_properties:
|
input : {
|
||||||
columns: columns-copy
|
# Used when giving permissions to users not currently in the
|
||||||
|
# list of permissions.
|
||||||
|
new-user: ""
|
||||||
|
new-user-permission: \read
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
modal = Modal {
|
self.project.tasks := void
|
||||||
+visible
|
|
||||||
content-render: (self) ->
|
|
||||||
h \div.form [
|
|
||||||
|
|
||||||
field [
|
unless self.project.extra_properties
|
||||||
label "Project title"
|
Column = (title, args) ->
|
||||||
|
self = {
|
||||||
|
title: title
|
||||||
|
id: UUID!
|
||||||
|
}
|
||||||
|
|
||||||
input {
|
for key, value of (args || {})
|
||||||
value: self.title
|
self[key] = value
|
||||||
oninput: (e) ->
|
|
||||||
self.title := e.target.value
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
# h \hr []
|
self
|
||||||
|
|
||||||
# bulma.field [
|
self.project.extra_properties = {
|
||||||
# bulma.label "Adding a user"
|
columns: [
|
||||||
# bulma.input {
|
Column "Unassigned" {color: "red"}
|
||||||
# value: self.new-user
|
Column "Work in Progress"
|
||||||
# oninput: (e) ->
|
Column "To be Checked"
|
||||||
# self.new-user := e.target.value
|
Column "Being Checked"
|
||||||
# name: \new-user
|
Column "Done" {color: "green"}
|
||||||
# id: \user-add
|
]
|
||||||
# }
|
}
|
||||||
# ]
|
|
||||||
|
|
||||||
h \hr []
|
self.modal = Modal {
|
||||||
|
on-validation: ->
|
||||||
|
if true # FIXME: Validate project
|
||||||
|
self.visible := false
|
||||||
|
|
||||||
field [
|
args.on-validation self.project
|
||||||
|
|
||||||
|
on-cancellation: ->
|
||||||
|
self.visible := false
|
||||||
|
|
||||||
|
content-render: -> [
|
||||||
|
field {key: \title} [
|
||||||
|
label "Title"
|
||||||
|
|
||||||
|
input {
|
||||||
|
value: self.project.title
|
||||||
|
oninput: (e) ->
|
||||||
|
console.log "oninput => ", e.target.value
|
||||||
|
self.project.title := e.target.value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
if self.project.permissions
|
||||||
|
field {key: \permissions} [
|
||||||
label "Permissions"
|
label "Permissions"
|
||||||
|
|
||||||
h \table.table.is-fullwidth.is-striped [
|
h \table.table.is-fullwidth [
|
||||||
|
h \thead [
|
||||||
|
h \th [ "User" ]
|
||||||
|
h \th [ "Permission" ]
|
||||||
|
]
|
||||||
h \tbody [
|
h \tbody [
|
||||||
for permission, uids of self.permissions
|
for permission in PERMISSION_LEVELS
|
||||||
for uid in uids
|
[
|
||||||
h \tr {key: uid.to-string!} [
|
for uid in self.project.permissions[permission]
|
||||||
h \td [
|
h \tr {key: uid} [
|
||||||
uid.to-string!
|
# FIXME: show full name or login
|
||||||
|
h \td [ uid.to-string! ]
|
||||||
|
h \td [ permission ]
|
||||||
]
|
]
|
||||||
|
]
|
||||||
h \td.is-narrow [
|
|
||||||
permission
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
h \hr []
|
if self.project.permissions
|
||||||
|
field \.has-addons [
|
||||||
# FIXME: This is supposed to go in a .field, right?
|
|
||||||
label "Adding new user"
|
|
||||||
|
|
||||||
field \.has-addons { key: \new-user } [
|
|
||||||
control [
|
|
||||||
select {
|
|
||||||
onchange: (e) ->
|
|
||||||
self.tmp.new-user-permission.permission := e.target.value
|
|
||||||
} permission-groups.map (permission) -> permission-to-form-selection self, permission
|
|
||||||
]
|
|
||||||
|
|
||||||
control \.is-expanded [
|
|
||||||
select \.is-fullwidth {
|
|
||||||
onchange: (e) ->
|
|
||||||
self.tmp.new-user-permission.uid := e.target.value
|
|
||||||
} [
|
|
||||||
user-form-selection self, { login: "Choose a user", uid: "-" }
|
|
||||||
for user-id, user of self.tmp.users
|
|
||||||
user-form-selection self, user
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
control [
|
|
||||||
button \.is-success.is-outlined {
|
|
||||||
onclick: ->
|
|
||||||
if self.tmp.new-user-permission.uid == void || self.tmp.new-user-permission.uid == "-"
|
|
||||||
console.log "adding an user permission on the kanban: failed, no user selected"
|
|
||||||
else
|
|
||||||
# TODO:
|
|
||||||
# adding the permissions in self.permissions
|
|
||||||
# then editing the project in the db via todod-ws
|
|
||||||
permissions-add self, self.tmp.new-user-permission.permission, self.tmp.new-user-permission.uid
|
|
||||||
} [ "+" ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
h \hr []
|
|
||||||
|
|
||||||
label [ "Columns" ]
|
|
||||||
|
|
||||||
for dom in (self.extra_properties.columns.map (column) -> col-to-lines column, self)
|
|
||||||
dom
|
|
||||||
|
|
||||||
h \hr []
|
|
||||||
|
|
||||||
field \.has-addons { key: \new-column } [
|
|
||||||
control \.is-expanded [
|
control \.is-expanded [
|
||||||
|
# FIXME: Replace by a “user search input” as soon
|
||||||
|
# as one is available.
|
||||||
input {
|
input {
|
||||||
value: self.tmp.new-column-input.title
|
value: self.input.new-user
|
||||||
oninput: (e) ->
|
oninput: (e) ->
|
||||||
self.tmp.new-column-input.title := e.target.value
|
self.input.new-user := e.target.value
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
control [
|
control [
|
||||||
button \.is-success.is-outlined {
|
select {
|
||||||
|
onchange: (e) ->
|
||||||
|
self.input.new-user-permission := e.target.value
|
||||||
|
} PERMISSION_LEVELS.map (perm) ->
|
||||||
|
h \option {
|
||||||
|
selected: perm == \read
|
||||||
|
} [ perm ]
|
||||||
|
]
|
||||||
|
|
||||||
|
control [
|
||||||
|
h \div.button.is-success.is-outlined {
|
||||||
onclick: ->
|
onclick: ->
|
||||||
new-col = {
|
uid = parse-int self.input.new-user
|
||||||
id: UUID!
|
perm = self.input.new-user-permission
|
||||||
title: self.tmp.new-column-input.title
|
|
||||||
}
|
self.input.new-user := ""
|
||||||
self.extra_properties.columns ++= [ new-col ]
|
# FIXME: Really? :thonk:
|
||||||
self.tmp.new-column-input.title := "New column !"
|
#self.input.new-user-permission := \read
|
||||||
} [ "+" ]
|
|
||||||
|
console.log "Adding new perm? :/", uid, perm
|
||||||
|
|
||||||
|
remove-permission self.project, uid
|
||||||
|
add-permission self.project, uid, perm
|
||||||
|
|
||||||
|
console.log self.project.permissions
|
||||||
|
} [
|
||||||
|
"+"
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
}
|
||||||
on-validation: ->
|
|
||||||
tmp = delete self.tmp
|
|
||||||
if project.id
|
|
||||||
todod-ws.edit-list project.id, self
|
|
||||||
else
|
|
||||||
todod-ws.add-list self.title, self
|
|
||||||
self.tmp := tmp
|
|
||||||
}, self
|
|
||||||
|
|
||||||
self.render = ->
|
self.render = ->
|
||||||
modal.render!
|
self.modal.visible = self.visible
|
||||||
|
|
||||||
|
self.modal.render!
|
||||||
|
|
||||||
self
|
self
|
||||||
|
|
||||||
|
@ -5,6 +5,12 @@ Task = require "./task.ls"
|
|||||||
Modal = require './modal.ls'
|
Modal = require './modal.ls'
|
||||||
TaskCreationModal = require './task-creation-modal.ls'
|
TaskCreationModal = require './task-creation-modal.ls'
|
||||||
ProjectCreationModal = require './project-creation-modal.ls'
|
ProjectCreationModal = require './project-creation-modal.ls'
|
||||||
|
ColumnEditModal = require './column-edit-modal.ls'
|
||||||
|
|
||||||
|
{icon} = require './font-awesome.ls'
|
||||||
|
|
||||||
|
deep-copy = (object) ->
|
||||||
|
JSON.parse JSON.stringify object
|
||||||
|
|
||||||
is-right-column = (task, column-id) ->
|
is-right-column = (task, column-id) ->
|
||||||
task.extra_properties && task.extra_properties.column && task.extra_properties.column == column-id
|
task.extra_properties && task.extra_properties.column && task.extra_properties.column == column-id
|
||||||
@ -43,7 +49,31 @@ Project = (self, todod-ws, users) ->
|
|||||||
h \div.column.cards-list {
|
h \div.column.cards-list {
|
||||||
key: column.id
|
key: column.id
|
||||||
} [
|
} [
|
||||||
h \p.title.is-4 [ column.title ]
|
h \p.title.is-4 [
|
||||||
|
column.title
|
||||||
|
|
||||||
|
h \a.is-pulled-right.icon.has-text-grey {
|
||||||
|
onclick: ->
|
||||||
|
modal := ColumnEditModal self, column, {
|
||||||
|
on-validation: (column) ->
|
||||||
|
console.log "column update:", column
|
||||||
|
modal.visible := false
|
||||||
|
|
||||||
|
extra_properties = deep-copy(self.extra_properties)
|
||||||
|
extra_properties.columns = extra_properties.columns.map (old-column) ->
|
||||||
|
if old-column.id == column.id
|
||||||
|
column
|
||||||
|
else
|
||||||
|
old-column
|
||||||
|
|
||||||
|
todod-ws.edit-list self.id, {
|
||||||
|
extra_properties: extra_properties
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} [
|
||||||
|
icon \cog
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
tasks-to-display.map (task) ->
|
tasks-to-display.map (task) ->
|
||||||
task.render {
|
task.render {
|
||||||
@ -61,37 +91,44 @@ Project = (self, todod-ws, users) ->
|
|||||||
|
|
||||||
self.right-nav-render = ->
|
self.right-nav-render = ->
|
||||||
[
|
[
|
||||||
h \div.navbar-item {
|
h \a.navbar-item.has-text-success {
|
||||||
key: "navbar-new-task"
|
key: "navbar-new-task"
|
||||||
|
onclick: ->
|
||||||
|
modal := TaskCreationModal self, self.todod-ws, void, self.users
|
||||||
} [
|
} [
|
||||||
h \div.button.is-success.is-outlined.is-medium {
|
h \span [ "New task" ]
|
||||||
onclick: ->
|
|
||||||
modal := TaskCreationModal self, self.todod-ws, void, self.users
|
icon \plus
|
||||||
} [ "New task" ]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
h \div.navbar-item {
|
h \a.navbar-item {
|
||||||
key: "navbar-edit-project"
|
key: "navbar-edit-project"
|
||||||
|
onclick: ->
|
||||||
|
modal := ProjectCreationModal {
|
||||||
|
project: self
|
||||||
|
|
||||||
|
on-validation: (project) ->
|
||||||
|
console.log "Requesting edit for", project
|
||||||
|
self.todod-ws.edit-list project.id, project
|
||||||
|
}
|
||||||
} [
|
} [
|
||||||
h \div.button.is-dark.is-outlined.is-medium {
|
icon \cog
|
||||||
onclick: ->
|
# "Edit this project"
|
||||||
modal := ProjectCreationModal self, self.todod-ws, self.users
|
|
||||||
} [ "Edit this project" ]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
h \div.navbar-item {
|
h \a.navbar-item.has-text-danger {
|
||||||
key: "navbar-delete-project"
|
key: "navbar-delete-project"
|
||||||
|
onclick: ->
|
||||||
|
modal := Modal {
|
||||||
|
+visible
|
||||||
|
content:
|
||||||
|
h \p [ "Are you sure you want to remove board #{self.title}?" ]
|
||||||
|
on-validation: ->
|
||||||
|
self.todod-ws.remove-list self.id
|
||||||
|
}
|
||||||
} [
|
} [
|
||||||
h \div.button.is-danger.is-outlined.is-medium {
|
icon \skull-crossbones
|
||||||
onclick: ->
|
# "Delete this project"
|
||||||
modal := Modal {
|
|
||||||
+visible
|
|
||||||
content:
|
|
||||||
h \p [ "Are you sure you want to remove board #{self.title}?" ]
|
|
||||||
on-validation: ->
|
|
||||||
self.todod-ws.remove-list self.id
|
|
||||||
}
|
|
||||||
} [ "Delete this project" ]
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ nmd = require "nano-markdown"
|
|||||||
TaskCreationModal = require './task-creation-modal.ls'
|
TaskCreationModal = require './task-creation-modal.ls'
|
||||||
TaskRemovalModal = require './task-removal-modal.ls'
|
TaskRemovalModal = require './task-removal-modal.ls'
|
||||||
|
|
||||||
|
{icon} = require "./font-awesome.ls"
|
||||||
|
|
||||||
display-login = (task, users) ->
|
display-login = (task, users) ->
|
||||||
if task.extra_properties && task.extra_properties.assignee-id && users && users[task.extra_properties.assignee-id] && users[task.extra_properties.assignee-id].login
|
if task.extra_properties && task.extra_properties.assignee-id && users && users[task.extra_properties.assignee-id] && users[task.extra_properties.assignee-id].login
|
||||||
h \p [ '@' + users[task.extra_properties.assignee-id].login ]
|
h \p [ '@' + users[task.extra_properties.assignee-id].login ]
|
||||||
@ -31,7 +33,15 @@ Task = (self, project, todod-ws) ->
|
|||||||
args.onclick(e)
|
args.onclick(e)
|
||||||
} [
|
} [
|
||||||
h \div.card-content [
|
h \div.card-content [
|
||||||
h \div.title.is-5 [ self.title ]
|
h \div.title.is-5 [
|
||||||
|
h \a.has-text-grey.is-pulled-right {
|
||||||
|
onclick: ->
|
||||||
|
modal := TaskCreationModal project, todod-ws, self, project.users
|
||||||
|
} [
|
||||||
|
icon \cog
|
||||||
|
]
|
||||||
|
self.title
|
||||||
|
]
|
||||||
h \div.media [
|
h \div.media [
|
||||||
h \div.media-left [
|
h \div.media-left [
|
||||||
# FIXME: assignee card image
|
# FIXME: assignee card image
|
||||||
@ -50,11 +60,6 @@ Task = (self, project, todod-ws) ->
|
|||||||
|
|
||||||
if args.is-selected
|
if args.is-selected
|
||||||
h \div.card-footer [
|
h \div.card-footer [
|
||||||
h \a.card-footer-item {
|
|
||||||
onclick: ->
|
|
||||||
modal := TaskCreationModal project, todod-ws, self, project.users
|
|
||||||
} [ "Edit" ]
|
|
||||||
|
|
||||||
h \a.card-footer-item.has-text-danger {
|
h \a.card-footer-item.has-text-danger {
|
||||||
onclick: ->
|
onclick: ->
|
||||||
modal := TaskRemovalModal project.id, todod-ws, self
|
modal := TaskRemovalModal project.id, todod-ws, self
|
||||||
|
@ -21,6 +21,7 @@ module.exports = {
|
|||||||
"edit-task": 9
|
"edit-task": 9
|
||||||
"subscribe": 10
|
"subscribe": 10
|
||||||
"unsubscribe": 11
|
"unsubscribe": 11
|
||||||
|
"set-permission": 12
|
||||||
}
|
}
|
||||||
|
|
||||||
response-types = {
|
response-types = {
|
||||||
@ -70,6 +71,8 @@ module.exports = {
|
|||||||
message = JSON.parse(event.data)
|
message = JSON.parse(event.data)
|
||||||
parsed-message = JSON.parse(message.payload)
|
parsed-message = JSON.parse(message.payload)
|
||||||
|
|
||||||
|
console.log "received todod message:", parsed-message
|
||||||
|
|
||||||
for f in self.callbacks[message.mtype]
|
for f in self.callbacks[message.mtype]
|
||||||
f parsed-message
|
f parsed-message
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<title>Kanban</title>
|
<title>Kanban</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<link rel="stylesheet" href="/font-awesome/fontawesome.min.css"/>
|
<link rel="stylesheet" href="/font-awesome/css/fontawesome.min.css"/>
|
||||||
<link rel="stylesheet" href="/font-awesome/solid.min.css"/>
|
<link rel="stylesheet" href="/font-awesome/css/solid.min.css"/>
|
||||||
<link rel="stylesheet" href="/style.css"/>
|
<link rel="stylesheet" href="/style.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
Loading…
Reference in New Issue
Block a user