UI improvement && logic code for people Webpage (#33)

* fix checkout alignmnet

* fixed create identity issue

* added logic for edit identity as well as create identity

* final changes

* UX changes

* minor fixes

* Signed Create identity is working now

* minor changes

* friend node profile pic is aligned now

* People->Edit && create identity popup responsive

* updated & refactor code

* changes added

* Update people_ownids.js

* Update people_util.js

* feat: people Web page  UI

* minor-fix

* fix prettier & eslint issue

* updated changes

* updated changes

* minor fix

* update changes
This commit is contained in:
Avinash Kumar 2021-04-27 00:08:15 +05:30 committed by GitHub
parent f09d6b0ca9
commit 53fa5aeec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 282 additions and 128 deletions

View File

@ -1,60 +1,57 @@
{
"root": true,
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly",
"window": "readonly",
"document": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018
},
"ignorePatterns": ["mithril.js", "assets/*", "make-src/*"],
"rules": {
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"arrow-spacing": ["error", { "before": true, "after": true }],
"arrow-parens": ["error", "always"],
"comma-style": ["error", "last"],
"comma-spacing": ["error", { "before": false, "after": true }],
"camelcase": ["error", {
"allow": ["^UNSAFE_"],
"properties": "never",
"ignoreGlobals": true
}],
"eol-last": "error",
"eqeqeq": ["error", "always", { "null": "ignore" }],
"no-irregular-whitespace": ["error"],
"no-trailing-spaces": ["error"],
"no-unexpected-multiline": ["error"],
"no-unreachable": ["error"],
"no-var": "warn",
"no-unused-vars": ["error", {
"args": "none",
"caughtErrors": "none",
"ignoreRestSiblings": true,
"vars": "all"
}],
"no-use-before-define": ["warn", { "functions": true, "classes": false }],
"object-shorthand": "error",
"prefer-const": ["error", { "destructuring": "all" }],
"semi-style": ["warn", "last"],
"spaced-comment": ["warn", "always"]
}
"root": true,
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly",
"window": "readonly",
"document": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018
},
"ignorePatterns": ["mithril.js", "assets/*", "make-src/*"],
"rules": {
"linebreak-style": ["off", "unix"],
"quotes": ["error", "single"],
"semi": ["error", "always"],
"arrow-spacing": ["error", { "before": true, "after": true }],
"arrow-parens": ["error", "always"],
"comma-style": ["error", "last"],
"comma-spacing": ["error", { "before": false, "after": true }],
"camelcase": [
"error",
{
"allow": ["^UNSAFE_"],
"properties": "never",
"ignoreGlobals": true
}
],
"eol-last": "error",
"eqeqeq": ["error", "always", { "null": "ignore" }],
"no-irregular-whitespace": ["error"],
"no-trailing-spaces": ["error"],
"no-unexpected-multiline": ["error"],
"no-unreachable": ["error"],
"no-var": "warn",
"no-unused-vars": [
"error",
{
"args": "none",
"caughtErrors": "none",
"ignoreRestSiblings": true,
"vars": "all"
}
],
"no-use-before-define": ["warn", { "functions": true, "classes": false }],
"object-shorthand": "error",
"prefer-const": ["error", { "destructuring": "all" }],
"semi-style": ["warn", "last"],
"spaced-comment": ["warn", "always"]
}
}

View File

@ -279,6 +279,7 @@ const Lobby = () => {
ChatLobbyModel.selected(info, '.selected-lobby', tagname),
{
key: info.lobby_id.xstr64,
onclick,
},
[

View File

@ -25,6 +25,7 @@ const DownloadDirectory = () => {
let dlDir = '';
const setDir = () => {
// const path = document.getElementById('dl-dir-input').value; // unused?
rs.rsJsonApiRequest(
'rsFiles/setDownloadDirectory',
{
@ -54,6 +55,7 @@ const PartialsDirectory = () => {
let partialsDir = '';
const setDir = () => {
// const path = document.getElementById('partial-dir-input').value; // unused?
rs.rsJsonApiRequest(
'rsFiles/setPartialsDirectory',
{

View File

@ -3,10 +3,13 @@ const rs = require('rswebui');
const util = require('config/config_util'); // for future use
/* eslint-disable no-unused-vars */ const SetNwMode = () => {
/* eslint-disable no-unused-vars */
const SetNwMode = () => {
let mode = undefined;
let sslId = undefined;
const setMode = () => rs.rsJsonApiRequest('/');
return {
oninit: util.getSslId().then((val) => {
sslId = val;
@ -123,6 +126,7 @@ const Component = () => {
m('.widget.widget-half', [
m('h3', 'Network Configuration'),
m('hr'),
m('.grid-2col', [
m(SetLimits),
m(SetOpMode),

View File

@ -1,4 +1,5 @@
const m = require('mithril');
const widget = require('widgets');
const sections = {

View File

@ -3,6 +3,7 @@ const rs = require('rswebui');
const servicesInfo = {
list: [],
setData(data) {
servicesInfo.list = data.info.mServiceList;
},

View File

@ -87,6 +87,7 @@ function addFile(url) {
{
fileName: details.name,
hash: details.hash,
flags: util.RS_FILE_REQ_ANONYMOUS_ROUTING,
size: Number.parseInt(details.size),
},

View File

@ -1,4 +1,5 @@
const m = require('mithril');
const widget = require('widgets');
const downloads = require('files/files_downloads');

View File

@ -92,6 +92,7 @@ function actionButton(file, action) {
'button',
{
title: 'resume',
onclick() {
fileAction(file.hash, 'resume');
},
@ -104,6 +105,7 @@ function actionButton(file, action) {
'button',
{
title: 'pause',
onclick() {
fileAction(file.hash, 'pause');
},
@ -116,6 +118,7 @@ function actionButton(file, action) {
'button.red',
{
title: 'cancel',
onclick() {
fileAction(file.hash, 'cancel');
},

View File

@ -59,6 +59,7 @@ function loginComponent() {
},
'Login'
);
const inputPassword = () =>
m('input[autofocus]', {
id: 'password',
@ -68,7 +69,9 @@ function loginComponent() {
onkeydown: (e) => {
if (e.keyCode === 13) {
passwd = e.target.value;
buttonLogin().click();
return false;
}
return true;

View File

@ -1,4 +1,5 @@
const m = require('mithril');
const util = require('mail/mail_util');
const Layout = () => {

View File

@ -51,6 +51,7 @@ module.exports = {
view: (v) => {
const tab = v.attrs.tab;
// TODO: utilize multiple routing params
if (Object.prototype.hasOwnProperty.call(v.attrs, 'msgId')) {
return m(
Layout,

View File

@ -1,4 +1,5 @@
const m = require('mithril');
const util = require('mail/mail_util');
const Layout = () => {

View File

@ -27,7 +27,9 @@ const MessageSummary = () => {
(data) => {
details = data.msg;
files = details.files;
isStarred = (details.msgflags & 0xf00) === RS_MSG_STAR;
const flag = details.msgflags & 0xf0;
if (flag === RS_MSG_NEW || flag === RS_MSG_UNREAD_BY_USER) {
msgStatus = 'unread';
@ -78,6 +80,7 @@ const MessageSummary = () => {
// m('td', details.rspeerid_srcId == 0 ?
// '[Notification]' :
// peopleUtils.getInfo(details.rspeerid_srcId)), // getInfo previously uses "/rsIdentity/getIdentitiesInfo"
m('td', new Date(details.ts * 1000).toLocaleString()),
]
),

View File

@ -3,7 +3,7 @@ const m = require('mithril');
const login = require('login');
const home = require('home');
const network = require('network/network');
const people = require('people/people');
const people = require('people/people_resolver');
const chat = require('chat/chat');
const mail = require('mail/mail_resolver');
const files = require('files/files_resolver');
@ -49,7 +49,7 @@ const Layout = () => {
links: {
home: '/home',
network: '/network',
people: '/people',
people: '/people/OwnIdentity',
chat: '/chat',
mail: '/mail/inbox',
files: '/files/files',
@ -72,8 +72,9 @@ m.route(document.getElementById('main'), '/', {
'/network': {
render: () => m(Layout, m(network)),
},
'/people': {
render: () => m(Layout, m(people)),
'/people/:tab': {
render: (v) => m(Layout, m(people, v.attrs)),
},
'/chat/:lobby/:subaction': {
render: (v) => m(Layout, m(chat, v.attrs)),

View File

@ -122,11 +122,6 @@ const FriendsList = () => {
return {
oninit: () => {
Data.refreshGpgDetails();
// rs.setBackgroundTask(
// Data.refreshGpgDetails,
// 10000,
// () => m.route.get() === '/network',
// )
},
view: () =>
m('.widget', [

View File

@ -17,7 +17,10 @@ async function loadSslDetails() {
return sslDetails;
}
async function freshGpgDetails() {
const Data = {
gpgDetails: {},
};
Data.refreshGpgDetails = async function () {
const details = {};
const sslDetails = await loadSslDetails();
await Promise.all(
@ -52,14 +55,6 @@ async function freshGpgDetails() {
});
})
);
return details;
}
const Data = {
gpgDetails: {},
refreshGpgDetails() {
Data.gpgDetails = freshGpgDetails();
},
Data.gpgDetails = details;
};
module.exports = Data;

View File

@ -1,38 +1,23 @@
const m = require('mithril');
const rs = require('rswebui');
const peopleOwnIds = require('people/people_ownids');
const peopleUtil = require('people/people_util');
const AllContacts = {
oninit: () => {},
view: () => {
const list = peopleUtil.sortUsers(rs.userList.users);
return m('.widget', [
m('h3', 'Contacts', m('span.counter', list.length)),
m('hr'),
list.map((id) =>
m(
'.id',
{
key: id.mGroupId,
title: 'ID: ' + id.mGroupId,
},
id.mGroupName,
m('i.chatInit.fa.fa-comment-medical', {
title: 'start distant chat with ' + id.mGroupName + ' (' + id.mGroupId + ')',
onclick: () => {
m.route.set('/chat/:userid/createdistantchat', { userid: id.mGroupId });
},
})
)
),
]);
},
const AllContacts = () => {
const list = peopleUtil.sortUsers(rs.userList.users);
return {
view: () => {
return m('.widget', [
m('h3', 'Contacts', m('span.counter', list.length)),
m('hr'),
list.map((id) => m(peopleUtil.regularcontactInfo, { id })),
]);
},
};
};
const Layout = {
view: (vnode) => m('.tab-page', [m(peopleOwnIds), m(AllContacts)]),
view: (vnode) => m('.tab-page', [m(peopleUtil.SearchBar), m(AllContacts)]),
};
module.exports = {

View File

@ -0,0 +1,26 @@
const m = require('mithril');
const rs = require('rswebui');
const peopleUtil = require('people/people_util');
const MyContacts = () => {
const list = peopleUtil.contactlist(rs.userList.users);
return {
view: () => {
return m('.widget', [
m('h3', 'MyContacts', m('span.counter', list.length)),
m('hr'),
list.map((id) => m(peopleUtil.regularcontactInfo, { id })),
]);
},
};
};
const Layout = {
view: (vnode) => m('.tab-page', [m(peopleUtil.SearchBar), m(MyContacts)]),
};
module.exports = {
view: (vnode) => {
return m(Layout);
},
};

View File

@ -201,7 +201,9 @@ const EditIdentity = () => {
'/rsIdentity/updateIdentity',
{
id: v.attrs.details.mId,
name,
// avatar: v.attrs.details.mAvatar.mData.base64,
pseudonimous: true,
},
@ -255,10 +257,6 @@ const DeleteIdentity = () => {
const Identity = () => {
let details = {};
let avatarURI = {
view: () => [],
};
return {
oninit: (v) =>
rs.rsJsonApiRequest(
@ -268,9 +266,6 @@ const Identity = () => {
},
(data) => {
details = data.details;
// Creating URI during fetch because `details` is uninitialized
// during view run, due to request being async.
avatarURI = peopleUtil.createAvatarURI(data.details.mAvatar);
}
),
view: (v) =>
@ -281,7 +276,7 @@ const Identity = () => {
},
[
m('h4', details.mNickname),
m(avatarURI),
m(peopleUtil.UserAvatar, { avatar: details.mAvatar }),
m('.details', [
m('p', 'ID:'),
m('p', details.mId),

View File

@ -0,0 +1,26 @@
const m = require('mithril');
const widget = require('widgets');
const sections = {
OwnIdentity: require('people/people_ownids'),
MyContacts: require('people/people_own_contacts'),
All: require('people/people'),
};
const Layout = {
view: (vnode) =>
m('.tab-page', [
m(widget.Sidebar, {
tabs: Object.keys(sections),
baseRoute: '/people/',
}),
m('.node-panel', vnode.children),
]),
};
module.exports = {
view: (vnode) => {
const tab = vnode.attrs.tab;
return m(Layout, m(sections[tab]));
},
};

View File

@ -1,13 +1,44 @@
const m = require('mithril');
const rs = require('rswebui');
const m = require('mithril');
function checksudo(id) {
return id === '0000000000000000';
}
const UserAvatar = () => ({
view: (v) => {
const imageURI = v.attrs.avatar;
console.log(imageURI);
return imageURI === undefined || imageURI.mData.base64 === ''
? []
: m('img.avatar', {
src: 'data:image/png;base64,' + imageURI.mData.base64,
});
},
});
function contactlist(list) {
const result = [];
if (list !== undefined) {
list.map((id) => {
id.isSearched = true;
rs.rsJsonApiRequest('/rsIdentity/isARegularContact', { id: id.mGroupId }, (data) => {
if (data.retval) result.push(id);
console.log(data);
});
});
}
return result;
}
function sortUsers(list) {
if (list !== undefined) {
const result = [...list];
const result = [];
list.map((id) => {
id.isSearched = true;
result.push(id);
});
result.sort((a, b) => a.mGroupName.localeCompare(b.mGroupName));
return result;
}
@ -17,6 +48,7 @@ function sortUsers(list) {
function sortIds(list) {
if (list !== undefined) {
const result = [...list];
result.sort((a, b) => rs.userList.username(a).localeCompare(rs.userList.username(b)));
return result;
}
@ -34,24 +66,99 @@ function ownIds(consumer = (list) => {}, onlySigned = false) {
}
});
}
const SearchBar = () => {
let searchString = '';
function createAvatarURI(avatar) {
return avatar.mData.base64 === ''
? {
view: () => [],
}
: {
view: () =>
m('img.avatar', {
src: 'data:image/png;base64,' + avatar.mData.base64,
}),
};
}
return {
view: () =>
m('input.searchbar', {
type: 'text',
placeholder: 'search',
value: searchString,
oninput: (e) => {
searchString = e.target.value.toLowerCase();
rs.userList.users.map((id) => {
if (id.mGroupName.toLowerCase().indexOf(searchString) > -1) {
id.isSearched = true;
} else {
id.isSearched = false;
}
});
},
}),
};
};
const regularcontactInfo = () => {
let details = {};
return {
oninit: (v) =>
rs.rsJsonApiRequest(
'/rsIdentity/getIdDetails',
{
id: v.attrs.id.mGroupId,
},
(data) => {
details = data.details;
}
),
view: (v) =>
m(
'.identity',
{
key: details.mId,
style: 'display:' + (v.attrs.id.isSearched ? 'block' : 'none'),
},
[
m('h4', details.mNickname),
m(UserAvatar, { avatar: details.mAvatar }),
m('.details', [
m('p', 'ID:'),
m('p', details.mId),
m('p', 'Type:'),
m('p', details.mFlags === 14 ? 'Signed ID' : 'Anonymous ID'),
m('p', 'Owner node ID:'),
m('p', details.mPgpId),
m('p', 'Created on:'),
m(
'p',
typeof details.mPublishTS === 'object'
? new Date(details.mPublishTS.xint64 * 1000).toLocaleString()
: 'undefiend'
),
m('p', 'Last used:'),
m(
'p',
typeof details.mLastUsageTS === 'object'
? new Date(details.mLastUsageTS.xint64 * 1000).toLocaleDateString()
: 'undefiend'
),
]),
m(
'button',
{
onclick: () =>
m.route.set('/chat/:userid/createdistantchat', {
userid: v.attrs.id.mGroupId,
}),
},
'Chat'
),
m('button.red', {}, 'Mail'),
]
),
};
};
module.exports = {
sortUsers,
sortIds,
ownIds,
createAvatarURI,
checksudo,
UserAvatar,
contactlist,
SearchBar,
regularcontactInfo,
};

View File

@ -1,3 +1,4 @@
const m = require('mithril');
const API_URL = 'http://127.0.0.1:9092';
@ -50,6 +51,7 @@ function rsJsonApiRequest(
serialize: handleSerialize,
headers,
body: data,
config,
})
.then((result) => {
@ -107,6 +109,7 @@ const eventQueue = {
types: {
// #define RS_CHAT_TYPE_PUBLIC 1
// #define RS_CHAT_TYPE_PRIVATE 2
2: (chatId) => chatId.distant_chat_id, // distant chat (initiate? -> todo accept)
// #define RS_CHAT_TYPE_LOBBY 3
3: (chatId) => chatId.lobby_id.xstr64, // lobby_id
@ -120,6 +123,7 @@ const eventQueue = {
computeIfMissing(
computeIfMissing(owner.messages, chatId.type),
keyfn(chatId),
() => []
)
)