Merge branch 'master' into mp/chat/firefox-take-2

This commit is contained in:
Liam Fitzgerald 2020-04-17 12:06:34 +10:00
commit 41be649764
20 changed files with 130 additions and 81 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:9c47244803d87e8ab25bc257d34336ae72e9155a5400e5635a6a5f3ae608b239 oid sha256:418f7512f9ff24de9c222cb4f666ef892c35376c7ee50f9f9e389c7ffa4711fc
size 9952079 size 10010102

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c8dfc019cdf53e0d627e1afad91e4c9cd092f767c6ba0c8c9864dd422a14d814 oid sha256:9d131da321b891c126f62cc587c5e27c257695ff9ae15e502356159fba7f9bf3
size 1234152 size 1234415

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8ebc16b420b2ce8e8bf7e6b0c611a102355f9ec013475da3cf66cc078f35e4b3 oid sha256:816bb2cb6b59153c611ef8bc5342c2e02eb5ef3514f8f510c5aa2387df92e9a9
size 12458781 size 12470565

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,17 @@
class Channel { class Channel {
constructor() { constructor() {
this.init();
this.deleteOnUnload();
// a way to handle channel errors
//
//
this.onChannelError = (err) => {
console.error('event source error: ', err);
};
}
init() {
// unique identifier: current time and random number // unique identifier: current time and random number
// //
this.uid = this.uid =
@ -40,8 +52,10 @@ class Channel {
// disconnect function may be called exactly once. // disconnect function may be called exactly once.
// //
this.outstandingSubscriptions = new Map(); this.outstandingSubscriptions = new Map();
}
this.deleteOnUnload(); setOnChannelError(onError = (err) => {}) {
this.onChannelError = onError;
} }
deleteOnUnload() { deleteOnUnload() {
@ -196,8 +210,9 @@ class Channel {
} }
this.eventSource.onerror = e => { this.eventSource.onerror = e => {
console.error("eventSource error:", e);
this.delete(); this.delete();
this.init();
this.onChannelError(e);
} }
} }

View File

@ -344,9 +344,11 @@
=* loop-whos $ =* loop-whos $
?~ whos loop-socs(socs t.socs) ?~ whos loop-socs(socs t.socs)
=^ caz state =^ caz state
?: ?=(%remove -.upd) ?. ?=(%remove -.upd)
(leave-from-peer i.socs pax.upd i.whos) (listen-to-peer i.socs pax.upd i.whos)
(listen-to-peer i.socs pax.upd i.whos) ?: =(our.bowl i.whos)
(handle-listen-action %leave i.socs)
(leave-from-peer i.socs pax.upd i.whos)
loop-whos(whos t.whos, cards (weld cards caz)) loop-whos(whos t.whos, cards (weld cards caz))
:: ::
:: link subscriptions :: link subscriptions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -35,7 +35,7 @@
=/ dbug =/ dbug
!<(poke vase) !<(poke vase)
=; =tang =; =tang
((slog tang) [~ this]) ((%*(. slog pri 1) tang) [~ this])
?- -.dbug ?- -.dbug
%bowl [(sell !>(bowl))]~ %bowl [(sell !>(bowl))]~
:: ::
@ -47,6 +47,9 @@
(ream grab.dbug) (ream grab.dbug)
:: ::
%incoming %incoming
=; =tang
?^ tang tang
[%leaf "no matching subscriptions"]~
%+ murn %+ murn
%+ sort ~(tap by sup.bowl) %+ sort ~(tap by sup.bowl)
|= [[* a=[=ship =path]] [* b=[=ship =path]]] |= [[* a=[=ship =path]] [* b=[=ship =path]]]
@ -66,6 +69,9 @@
== ==
:: ::
%outgoing %outgoing
=; =tang
?^ tang tang
[%leaf "no matching subscriptions"]~
%+ murn %+ murn
%+ sort ~(tap by wex.bowl) %+ sort ~(tap by wex.bowl)
|= [[[a=wire *] *] [[b=wire *] *]] |= [[[a=wire *] *] [[b=wire *] *]]

View File

@ -40,6 +40,10 @@
== ==
++ both-parser ++ both-parser
;~ pose ;~ pose
%+ cook
|= [author=@ date-created=@da content=@t]
^- comment
[author date-created content %.n]
new-parser new-parser
%+ cook %+ cook
|= [author=@ @ @ date-created=@da @ content=@t] |= [author=@ @ @ date-created=@da @ content=@t]

View File

@ -3165,10 +3165,12 @@
?~ q.parsed ?~ q.parsed
=/ =path (rail-to-path source-rail) =/ =path (rail-to-path source-rail)
%- return-error %- return-error
:- :- %leaf =/ lyn p.p.parsed
%+ weld "ford: %hood: syntax error at " =/ col q.p.parsed
"[{<p.p.parsed>} {<q.p.parsed>}] in {<path>}" :~ leaf+(runt [(dec col) '-'] "^")
~ leaf+(trip (snag (dec lyn) (to-wain:format q.q.as-cage)))
leaf+"ford: %hood: syntax error at [{<lyn>} {<col>}] in {<path>}"
==
:: ::
(return-result %success %hood p.u.q.parsed) (return-result %success %hood p.u.q.parsed)
:: ::

View File

@ -77,7 +77,7 @@ export class ChatScreen extends Component {
); );
} else if (props.chatInitialized && } else if (props.chatInitialized &&
!(props.station in props.inbox) && !(props.station in props.inbox) &&
!(props.station in props.chatSynced) ) { (!!props.chatSynced && !(props.station in props.chatSynced))) {
props.history.push("/~chat"); props.history.push("/~chat");
} else if ( } else if (
@ -241,7 +241,7 @@ export class ChatScreen extends Component {
} }
let pendingMessages = props.pendingMessages.has(props.station) let pendingMessages = props.pendingMessages.has(props.station)
? props.pendingMessages.get(props.station).reverse() ? props.pendingMessages.get(props.station)
: []; : [];
pendingMessages.map(function (value) { pendingMessages.map(function (value) {
@ -302,12 +302,14 @@ export class ChatScreen extends Component {
<div <div
className="overflow-y-scroll bg-white bg-gray0-d pt3 pb2 flex flex-column-reverse" className="overflow-y-scroll bg-white bg-gray0-d pt3 pb2 flex flex-column-reverse"
style={{ height: "100%", resize: "vertical" }} style={{ height: "100%", resize: "vertical" }}
onScroll={this.onScroll}
> >
<div <div
ref={el => { ref={el => {
this.scrollElement = el; this.scrollElement = el;
}}></div> }}></div>
{( {(
props.chatSynced &&
!(props.station in props.chatSynced) && !(props.station in props.chatSynced) &&
(messages.length > 0) (messages.length > 0)
) ? ( ) ? (
@ -320,7 +322,7 @@ export class ChatScreen extends Component {
{messageElements} {messageElements}
</div> </div>
)} )}
} }
render() { render() {
const { props, state } = this; const { props, state } = this;

View File

@ -22,12 +22,11 @@ export class JoinScreen extends Component {
componentDidMount() { componentDidMount() {
const { props } = this; const { props } = this;
if (props.autoJoin !== "/undefined/undefined" && if (props.autoJoin !== "/undefined/undefined" &&
props.autoJoin !== "/~/undefined/undefined") { props.autoJoin !== "/~/undefined/undefined") {
let station = props.autoJoin.split('/'); let station = props.autoJoin.split('/');
let sig = props.autoJoin.includes("/~/"); let sig = props.autoJoin.includes("/~/");
let ship = !!sig ? station[2] : station[1]; let ship = !!sig ? station[2] : station[1];
station = station.join('/');
if ( if (
station.length < 2 || station.length < 2 ||
(!!sig && station.length < 3) || (!!sig && station.length < 3) ||
@ -38,7 +37,7 @@ export class JoinScreen extends Component {
}); });
return; return;
} }
station = props.autoJoin;
this.setState({ this.setState({
station, station,
@ -50,7 +49,7 @@ export class JoinScreen extends Component {
componentDidUpdate(prevProps, prevState) { componentDidUpdate(prevProps, prevState) {
const { props, state } = this; const { props, state } = this;
if (state.station in props.inbox || if (state.station in props.inbox ||
props.chatSynced !== prevProps.chatSynced) { (props.chatSynced !== prevProps.chatSynced && state.station !== '/')) {
this.setState({ awaiting: false }); this.setState({ awaiting: false });
props.history.push(`/~chat/room${state.station}`); props.history.push(`/~chat/room${state.station}`);
} }
@ -59,24 +58,13 @@ export class JoinScreen extends Component {
onClickJoin() { onClickJoin() {
const { props, state } = this; const { props, state } = this;
let text = state.station; let station = state.station.split('/');
if (text in props.inbox || let sig = state.station.includes("/~/");
text.length === 0) {
this.setState({
error: true,
});
return;
}
let station = text.split('/');
let sig = state.station.includes("~/");
let ship = !!sig ? station[1] : station[0];
station = station.join('/');
let ship = !!sig ? station[2] : station[1];
if ( if (
(!sig && station.split('/').length < 2) || station.length < 2 ||
(!!sig && station.split('/').length < 3) || (!!sig && station.length < 3) ||
!urbitOb.isValidPatp(ship) !urbitOb.isValidPatp(ship)
) { ) {
this.setState({ this.setState({
@ -84,16 +72,19 @@ export class JoinScreen extends Component {
}); });
return; return;
} }
station = state.station.trim();
this.setState({ this.setState({
station,
awaiting: true, awaiting: true,
station: `/${station}` }, () => {
}, () => props.api.chatView.join(ship, `/${station}`, true)) props.api.chatView.join(ship, station, true)
});
} }
stationChange(event) { stationChange(event) {
this.setState({ this.setState({
station: event.target.value station: `/${event.target.value}`
}); });
} }

View File

@ -8,7 +8,11 @@ import { Sigil } from '/components/lib/icons/sigil';
import { uuid, uxToHex, hexToRgba } from '/lib/util'; import { uuid, uxToHex, hexToRgba } from '/lib/util';
const DEFAULT_INPUT_HEIGHT = 28;
// line height
const INPUT_LINE_HEIGHT = 28;
const INPUT_TOP_PADDING = 3;
function getAdvance(a, b) { function getAdvance(a, b) {
@ -103,7 +107,7 @@ export class ChatInput extends Component {
this.state = { this.state = {
message: '', message: '',
textareaHeight: DEFAULT_INPUT_HEIGHT, textareaHeight: INPUT_LINE_HEIGHT + INPUT_TOP_PADDING + 1,
patpSuggestions: [], patpSuggestions: [],
selectedSuggestion: null selectedSuggestion: null
}; };
@ -309,9 +313,8 @@ export class ChatInput extends Component {
} }
textareaInput() { textareaInput() {
const newHeight = this.textareaRef.current.scrollHeight < DEFAULT_INPUT_HEIGHT * 8 const maxHeight = INPUT_LINE_HEIGHT * 8 + INPUT_TOP_PADDING;
? `${this.textareaRef.current.scrollHeight}px` const newHeight = `${Math.min(maxHeight, this.textareaRef.current.scrollHeight)}px`;
: `${DEFAULT_INPUT_HEIGHT * 8}px`
this.setState({ this.setState({
textareaHeight: newHeight textareaHeight: newHeight
@ -418,7 +421,7 @@ export class ChatInput extends Component {
this.setState({ this.setState({
message: '', message: '',
textareaHeight: DEFAULT_INPUT_HEIGHT textareaHeight: INPUT_LINE_HEIGHT + INPUT_TOP_PADDING + 1
}); });
} }
@ -459,8 +462,8 @@ export class ChatInput extends Component {
</div> </div>
<div className="fr h-100 flex bg-gray0-d" style={{ flexGrow: 1 }}> <div className="fr h-100 flex bg-gray0-d" style={{ flexGrow: 1 }}>
<textarea <textarea
className={"pl3 bn bg-gray0-d white-d"} className={"pl3 bn bg-gray0-d white-d lh-copy"}
style={{ flexGrow: 1, height: state.textareaHeight, paddingTop: 6, resize: "none" }} style={{ flexGrow: 1, height: state.textareaHeight, paddingTop: INPUT_TOP_PADDING, resize: "none" }}
autoCapitalize="none" autoCapitalize="none"
autoFocus={( autoFocus={(
/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test( /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(

View File

@ -39,7 +39,7 @@ export class Root extends Component {
if (envelopes.length === 0) { if (envelopes.length === 0) {
messagePreviews[stat] = false; messagePreviews[stat] = false;
} else { } else {
messagePreviews[stat] = envelopes[envelopes.length - 1]; messagePreviews[stat] = envelopes[0];
} }
unreads[stat] = unreads[stat] =

View File

@ -9,9 +9,22 @@ import { LocalReducer } from '/reducers/local.js';
class Store { class Store {
constructor() { constructor() {
this.state = { this.state = this.initialState();
this.initialReducer = new InitialReducer();
this.permissionUpdateReducer = new PermissionUpdateReducer();
this.contactUpdateReducer = new ContactUpdateReducer();
this.chatUpdateReducer = new ChatUpdateReducer();
this.inviteUpdateReducer = new InviteUpdateReducer();
this.metadataReducer = new MetadataReducer();
this.localReducer = new LocalReducer();
this.setState = () => {};
}
initialState() {
return {
inbox: {}, inbox: {},
chatSynced: {}, chatSynced: null,
contacts: {}, contacts: {},
permissions: {}, permissions: {},
invites: {}, invites: {},
@ -24,15 +37,6 @@ class Store {
pendingMessages: new Map([]), pendingMessages: new Map([]),
chatInitialized: false chatInitialized: false
}; };
this.initialReducer = new InitialReducer();
this.permissionUpdateReducer = new PermissionUpdateReducer();
this.contactUpdateReducer = new ContactUpdateReducer();
this.chatUpdateReducer = new ChatUpdateReducer();
this.inviteUpdateReducer = new InviteUpdateReducer();
this.metadataReducer = new MetadataReducer();
this.localReducer = new LocalReducer();
this.setState = () => {};
} }
setStateHandler(setState) { setStateHandler(setState) {
@ -42,6 +46,11 @@ class Store {
handleEvent(data) { handleEvent(data) {
let json = data.data; let json = data.data;
if ('clear' in json && json.clear) {
this.setState(this.initialState());
return;
}
console.log(json); console.log(json);
this.initialReducer.reduce(json, this.state); this.initialReducer.reduce(json, this.state);
this.permissionUpdateReducer.reduce(json, this.state); this.permissionUpdateReducer.reduce(json, this.state);

View File

@ -13,11 +13,24 @@ export class Subscription {
start() { start() {
if (api.authTokens) { if (api.authTokens) {
this.firstRoundSubscription(); this.firstRoundSubscription();
window.urb.setOnChannelError(this.onChannelError.bind(this));
} else { } else {
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~"); console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
} }
} }
onChannelError(err) {
console.error('event source error: ', err);
console.log('initiating new channel');
this.firstRoundSubscriptionComplete = false;
setTimeout(2000, () => {
store.handleEvent({
data: { clear : true}
});
this.start();
});
}
subscribe(path, app) { subscribe(path, app) {
api.bind(path, 'PUT', api.authTokens.ship, app, api.bind(path, 'PUT', api.authTokens.ship, app,
this.handleEvent.bind(this), this.handleEvent.bind(this),

View File

@ -80,7 +80,6 @@ export class Root extends Component {
associations={associations} associations={associations}
invites={invites} invites={invites}
groups={groups} groups={groups}
rightPanelHide={true}
sidebarShown={state.sidebarShown} sidebarShown={state.sidebarShown}
selectedGroups={selectedGroups} selectedGroups={selectedGroups}
links={links} links={links}
@ -118,7 +117,6 @@ export class Root extends Component {
invites={invites} invites={invites}
groups={groups} groups={groups}
selected={resourcePath} selected={resourcePath}
rightPanelHide={true}
sidebarShown={state.sidebarShown} sidebarShown={state.sidebarShown}
selectedGroups={selectedGroups} selectedGroups={selectedGroups}
links={links} links={links}
@ -155,7 +153,6 @@ export class Root extends Component {
invites={invites} invites={invites}
groups={groups} groups={groups}
selected={resourcePath} selected={resourcePath}
rightPanelHide={true}
sidebarShown={state.sidebarShown} sidebarShown={state.sidebarShown}
selectedGroups={selectedGroups} selectedGroups={selectedGroups}
popout={popout} popout={popout}

View File

@ -167,7 +167,7 @@ a {
.cm-s-tlon span.cm-variable-3, .cm-s-tlon span.cm-type { color: black; } .cm-s-tlon span.cm-variable-3, .cm-s-tlon span.cm-type { color: black; }
.cm-s-tlon span.cm-property { color: black; } .cm-s-tlon span.cm-property { color: black; }
.cm-s-tlon span.cm-operator { color: black; } .cm-s-tlon span.cm-operator { color: black; }
.cm-s-tlon span.cm-comment { color: black; background-color: var(--light-gray); padding:2px; border-radius: 2px;} .cm-s-tlon span.cm-comment { color: black; background-color: var(--light-gray); display: inline-block; border-radius: 2px;}
.cm-s-tlon span.cm-string { color: var(--dark-gray); } .cm-s-tlon span.cm-string { color: var(--dark-gray); }
.cm-s-tlon span.cm-string-2 { color: var(--gray); } .cm-s-tlon span.cm-string-2 { color: var(--gray); }
.cm-s-tlon span.cm-qualifier { color: #555; } .cm-s-tlon span.cm-qualifier { color: #555; }
@ -362,10 +362,6 @@ md img {
background: #333; background: #333;
color: #fff; color: #fff;
} }
.CodeMirror-selected {
background: #4d4d4d !important;
color: white;
}
.cm-s-tlon span.cm-def { .cm-s-tlon span.cm-def {
color: white; color: white;
@ -392,12 +388,7 @@ md img {
color: white; color: white;
} }
.cm-s-tlon span.cm-comment {
color: black;
background-color: var(--gray);
padding: 2px;
border-radius: 2px;
}
.cm-s-tlon span.cm-string { .cm-s-tlon span.cm-string {
color: var(--gray); color: var(--gray);
} }
@ -417,4 +408,18 @@ md img {
.cm-s-tlon span.cm-link { .cm-s-tlon span.cm-link {
color: var(--gray); color: var(--gray);
} }
}
/* set rules w/ both color & bg-color last to preserve legibility */
.CodeMirror-selected {
background: var(--medium-gray) !important;
color: white;
}
.cm-s-tlon span.cm-comment {
color: black;
display: inline-block;
padding: 0;
background-color: rgba(255,255,255, 0.3);
border-radius: 2px;
}
}