Fixed some bookmark icon related issues

master
WolverinDEV 2021-06-11 11:43:53 +02:00
parent b524fdeb5c
commit ebc5b178e0
12 changed files with 98 additions and 38 deletions

View File

@ -3,6 +3,8 @@
- Fixed the bug that cause the file transfer to timeout if the user hasn't been quick enough to save his file - Fixed the bug that cause the file transfer to timeout if the user hasn't been quick enough to save his file
- Fixed the emoji picker being cut off - Fixed the emoji picker being cut off
- Fixed the file transfer sidebar not working - Fixed the file transfer sidebar not working
- Instantly reflect changes to the server icon for the bookmark menu bar
- Fixed a bug which prevented the proper context menu appear within the bookmark manage modal
* **26.05.21** * **26.05.21**
- Fixed automated builds - Fixed automated builds

View File

@ -2,9 +2,10 @@ import {LogCategory, logError, logWarn} from "tc-shared/log";
import {tr, tra} from "tc-shared/i18n/localize"; import {tr, tra} from "tc-shared/i18n/localize";
import * as loader from "tc-loader"; import * as loader from "tc-loader";
import {Stage} from "tc-loader"; import {Stage} from "tc-loader";
import {ConnectionHandler} from "tc-shared/ConnectionHandler"; import {ConnectionHandler, ConnectionState} from "tc-shared/ConnectionHandler";
import {server_connections} from "tc-shared/ConnectionManager"; import {server_connections} from "tc-shared/ConnectionManager";
import {ServerProperties} from "tc-shared/tree/Server"; import {ServerProperties} from "tc-shared/tree/Server";
import {Registry} from "tc-events";
export const kUnknownHistoryServerUniqueId = "unknown"; export const kUnknownHistoryServerUniqueId = "unknown";
@ -44,10 +45,17 @@ export type ConnectionHistoryServerInfo = {
passwordProtected: boolean passwordProtected: boolean
} }
export interface ConnectionHistoryEvents {
notify_server_info_updated: { serverUniqueId: string, keys: (keyof ConnectionHistoryServerInfo)[] }
}
export class ConnectionHistory { export class ConnectionHistory {
readonly events: Registry<ConnectionHistoryEvents>;
private database: IDBDatabase; private database: IDBDatabase;
constructor() { } constructor() {
this.events = new Registry<ConnectionHistoryEvents>();
}
async initializeDatabase() { async initializeDatabase() {
const openRequest = indexedDB.open("connection-log", 1); const openRequest = indexedDB.open("connection-log", 1);
@ -306,16 +314,29 @@ export class ConnectionHistory {
return; return;
} }
await this.updateDatabaseServerInfo(serverUniqueId, databaseValue => { await this.updateDatabaseServerInfo(serverUniqueId, databaseValue => {
databaseValue.name = info.name; const changes: (keyof ConnectionHistoryServerInfo)[] = [];
databaseValue.iconId = info.iconId; const updateValue = (databaseKey: string, infoKey: keyof ConnectionHistoryServerInfo) => {
if(databaseValue[databaseKey] === info[infoKey]) {
return;
}
databaseValue.clientsOnline = info.clientsOnline; databaseValue[databaseKey] = info[infoKey];
databaseValue.clientsMax = info.clientsMax; changes.push(infoKey);
}
databaseValue.hostBannerUrl = info.hostBannerUrl updateValue("name", "name");
databaseValue.hostBannerMode = info.hostBannerMode; updateValue("iconId", "iconId");
updateValue("clientsOnline", "clientsOnline");
updateValue("clientsMax", "clientsMax");
updateValue("hostBannerUrl", "hostBannerUrl");
updateValue("hostBannerMode", "hostBannerMode");
if(changes.length > 0) {
this.events.fire("notify_server_info_updated", { serverUniqueId: serverUniqueId, keys: changes });
}
}); });
} }
@ -542,7 +563,15 @@ class ConnectionHistoryUpdateListener {
} }
private registerConnectionHandler(handler: ConnectionHandler) { private registerConnectionHandler(handler: ConnectionHandler) {
handler.channelTree.server.events.on("notify_properties_updated", event => { const events = this.listenerConnectionHandler[handler.handlerId] = [];
events.push(handler.channelTree.server.events.on("notify_properties_updated", event => {
switch(handler.connection_state) {
case ConnectionState.UNCONNECTED:
case ConnectionState.DISCONNECTING:
/* We don't want any changes here */
return;
}
if("virtualserver_unique_identifier" in event.updated_properties) { if("virtualserver_unique_identifier" in event.updated_properties) {
if(handler.currentConnectId > 0) { if(handler.currentConnectId > 0) {
this.history.updateConnectionServerUniqueId(handler.currentConnectId, event.server_properties.virtualserver_unique_identifier) this.history.updateConnectionServerUniqueId(handler.currentConnectId, event.server_properties.virtualserver_unique_identifier)
@ -573,7 +602,7 @@ class ConnectionHistoryUpdateListener {
break; break;
} }
} }
}); }));
} }
} }
@ -581,7 +610,7 @@ export let connectionHistory: ConnectionHistory;
let historyInfoListener: ConnectionHistoryUpdateListener; let historyInfoListener: ConnectionHistoryUpdateListener;
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, { loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
priority: 0, priority: 40,
name: "Chat history setup", name: "Chat history setup",
function: async () => { function: async () => {
if(!('indexedDB' in window)) { if(!('indexedDB' in window)) {

View File

@ -127,7 +127,7 @@ export class AppController {
} }
export let appViewController: AppController; export let appViewController: AppController;
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, { loader.register_task(Stage.LOADED, {
name: "app view", name: "app view",
function: async () => { function: async () => {
appViewController = new AppController(); appViewController = new AppController();
@ -137,5 +137,5 @@ loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
(window as any).AppController = AppController; (window as any).AppController = AppController;
(window as any).appViewController = appViewController; (window as any).appViewController = appViewController;
}, },
priority: 0 priority: 100
}); });

View File

@ -167,16 +167,6 @@ html:root {
right: 0; right: 0;
} }
.iconContainer {
margin-right: .25em;
display: flex;
flex-direction: column;
flex-shrink: 0;
flex-grow: 0;
}
.dropdownEntry { .dropdownEntry {
position: relative; position: relative;
@ -306,3 +296,10 @@ html:root {
-webkit-transform: rotate(45deg); -webkit-transform: rotate(45deg);
} }
} }
.iconContainer {
margin-right: .25em;
display: flex;
flex-direction: column;
}

View File

@ -23,6 +23,8 @@ import {connectionHistory} from "tc-shared/connectionlog/History";
import {RemoteIconInfo} from "tc-shared/file/Icons"; import {RemoteIconInfo} from "tc-shared/file/Icons";
import {spawnModalAddCurrentServerToBookmarks} from "tc-shared/ui/modal/bookmarks-add-server/Controller"; import {spawnModalAddCurrentServerToBookmarks} from "tc-shared/ui/modal/bookmarks-add-server/Controller";
import {getAudioBackend, OutputDevice} from "tc-shared/audio/Player"; import {getAudioBackend, OutputDevice} from "tc-shared/audio/Player";
import {ignorePromise} from "tc-shared/proto";
import {LogCategory, logTrace} from "tc-shared/log";
class InfoController { class InfoController {
private readonly mode: ControlBarMode; private readonly mode: ControlBarMode;
@ -34,6 +36,8 @@ class InfoController {
private handlerRegisteredEvents: (() => void)[] = []; private handlerRegisteredEvents: (() => void)[] = [];
private defaultRecorderListener: () => void; private defaultRecorderListener: () => void;
private bookmarkServerUniqueIds: string[] = [];
constructor(events: Registry<ControlBarEvents>, mode: ControlBarMode) { constructor(events: Registry<ControlBarEvents>, mode: ControlBarMode) {
this.events = events; this.events = events;
this.mode = mode; this.mode = mode;
@ -61,6 +65,16 @@ class InfoController {
this.sendVideoState("camera"); this.sendVideoState("camera");
})); }));
bookmarks.events.on(["notify_bookmark_edited", "notify_bookmark_created", "notify_bookmark_deleted", "notify_bookmarks_imported"], () => this.sendBookmarks()); bookmarks.events.on(["notify_bookmark_edited", "notify_bookmark_created", "notify_bookmark_deleted", "notify_bookmarks_imported"], () => this.sendBookmarks());
events.push(connectionHistory.events.on("notify_server_info_updated", event => {
if(this.bookmarkServerUniqueIds.indexOf(event.serverUniqueId) === -1) {
return;
}
if(event.keys.indexOf("iconId") !== -1) {
/* An icon for a bookmark has changed. Send the full new list. */
ignorePromise(this.sendBookmarks());
}
}));
events.push(getVideoDriver().getEvents().on("notify_device_list_changed", () => this.sendCameraList())); events.push(getVideoDriver().getEvents().on("notify_device_list_changed", () => this.sendCameraList()));
events.push(getRecorderBackend().getDeviceList().getEvents().on("notify_list_updated", () => this.sendMicrophoneList())); events.push(getRecorderBackend().getDeviceList().getEvents().on("notify_list_updated", () => this.sendMicrophoneList()));
events.push(defaultRecorderEvents.on("notify_default_recorder_changed", () => { events.push(defaultRecorderEvents.on("notify_default_recorder_changed", () => {
@ -202,7 +216,9 @@ class InfoController {
}); });
} }
/* Note: This method might be executed concurrently */
public async sendBookmarks() { public async sendBookmarks() {
this.bookmarkServerUniqueIds = [];
const bookmarkList = bookmarks.getOrderedRegisteredBookmarks(); const bookmarkList = bookmarks.getOrderedRegisteredBookmarks();
const parent: Bookmark[] = []; const parent: Bookmark[] = [];
@ -216,15 +232,17 @@ class InfoController {
let icon: RemoteIconInfo; let icon: RemoteIconInfo;
try { try {
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address"); const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address", true);
if(connectInfo) { if(connectInfo) {
this.bookmarkServerUniqueIds.push(connectInfo.serverUniqueId);
const info = await connectionHistory.queryServerInfo(connectInfo.serverUniqueId); const info = await connectionHistory.queryServerInfo(connectInfo.serverUniqueId);
if(info && info.iconId > 0) { if(info && info.iconId > 0) {
icon = { iconId: info.iconId, serverUniqueId: connectInfo.serverUniqueId }; icon = { iconId: info.iconId, serverUniqueId: connectInfo.serverUniqueId };
} }
} }
} catch (_) { } catch (error) {
/* no need for any error handling */ /* No need to warn in prod build */
logTrace(LogCategory.BOOKMARKS, "Failed to query last connect info: %o", error);
} }
parentList.push({ parentList.push({

View File

@ -1,5 +1,4 @@
import * as React from "react"; import * as React from "react";
import {ReactComponentBase} from "tc-shared/ui/react-elements/ReactComponentBase";
import {IconRenderer, RemoteIconRenderer} from "tc-shared/ui/react-elements/Icon"; import {IconRenderer, RemoteIconRenderer} from "tc-shared/ui/react-elements/Icon";
import {getIconManager, RemoteIconInfo} from "tc-shared/file/Icons"; import {getIconManager, RemoteIconInfo} from "tc-shared/file/Icons";
import {joinClassList} from "tc-shared/ui/react-elements/Helper"; import {joinClassList} from "tc-shared/ui/react-elements/Helper";

View File

@ -11,6 +11,7 @@ import {bookmarks} from "tc-shared/Bookmarks";
import {RemoteIconInfo} from "tc-shared/file/Icons"; import {RemoteIconInfo} from "tc-shared/file/Icons";
import {connectionHistory} from "tc-shared/connectionlog/History"; import {connectionHistory} from "tc-shared/connectionlog/History";
import {spawnModalAddCurrentServerToBookmarks} from "tc-shared/ui/modal/bookmarks-add-server/Controller"; import {spawnModalAddCurrentServerToBookmarks} from "tc-shared/ui/modal/bookmarks-add-server/Controller";
import {LogCategory, logTrace} from "tc-shared/log";
function renderConnectionItems() { function renderConnectionItems() {
const items: MenuBarEntry[] = []; const items: MenuBarEntry[] = [];
@ -52,7 +53,9 @@ function renderConnectionItems() {
return items; return items;
} }
let bookmarkServerUniqueIds: string[] = [];
async function renderBookmarkItems() { async function renderBookmarkItems() {
bookmarkServerUniqueIds = [];
const bookmarkList = bookmarks.getOrderedRegisteredBookmarks(); const bookmarkList = bookmarks.getOrderedRegisteredBookmarks();
const bookmarkItems: MenuBarEntry[] = []; const bookmarkItems: MenuBarEntry[] = [];
@ -66,15 +69,17 @@ async function renderBookmarkItems() {
let icon: RemoteIconInfo; let icon: RemoteIconInfo;
try { try {
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address"); const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address", true);
if(connectInfo) { if(connectInfo) {
bookmarkServerUniqueIds.push(connectInfo.serverUniqueId);
const info = await connectionHistory.queryServerInfo(connectInfo.serverUniqueId); const info = await connectionHistory.queryServerInfo(connectInfo.serverUniqueId);
if(info && info.iconId > 0) { if(info && info.iconId > 0) {
icon = { iconId: info.iconId, serverUniqueId: connectInfo.serverUniqueId }; icon = { iconId: info.iconId, serverUniqueId: connectInfo.serverUniqueId };
} }
} }
} catch (_) { } catch (error) {
/* no need for any error handling */ /* No need to warn in prod build */
logTrace(LogCategory.BOOKMARKS, "Failed to query last connect info: %o", error);
} }
parentList.push({ parentList.push({
@ -363,6 +368,16 @@ class MenuBarUpdateListener {
})); }));
this.generalHandlerEvents.push(server_connections.events().on("notify_active_handler_changed", () => updateMenuBar())); this.generalHandlerEvents.push(server_connections.events().on("notify_active_handler_changed", () => updateMenuBar()));
this.generalHandlerEvents.push(bookmarks.events.on(["notify_bookmark_deleted", "notify_bookmark_created", "notify_bookmark_edited", "notify_bookmarks_imported"], () => updateMenuBar())); this.generalHandlerEvents.push(bookmarks.events.on(["notify_bookmark_deleted", "notify_bookmark_created", "notify_bookmark_edited", "notify_bookmarks_imported"], () => updateMenuBar()));
this.generalHandlerEvents.push(connectionHistory.events.on("notify_server_info_updated", event => {
if(bookmarkServerUniqueIds.indexOf(event.serverUniqueId) === -1) {
return;
}
if(event.keys.indexOf("iconId") !== -1) {
/* An icon for a bookmark has changed. Send the menu bar with the new icons. */
updateMenuBar();
}
}));
server_connections.getAllConnectionHandlers().forEach(handler => this.registerHandlerEvents(handler)); server_connections.getAllConnectionHandlers().forEach(handler => this.registerHandlerEvents(handler));
} }

View File

@ -567,7 +567,7 @@ class BookmarkModalController {
} }
return this.bookmarkUniqueServerIds[bookmarkId] = (async () => { return this.bookmarkUniqueServerIds[bookmarkId] = (async () => {
const info = await connectionHistory.lastConnectInfo(bookmark.serverAddress, "address"); const info = await connectionHistory.lastConnectInfo(bookmark.serverAddress, "address", true);
if(!info) { if(!info) {
return undefined; return undefined;
} }

View File

@ -109,7 +109,7 @@ const BookmarkListEntryRenderer = React.memo((props: { entry: BookmarkListEntry
events.fire("action_connect", { uniqueId: props.entry.uniqueId, newTab: false, closeModal: true }); events.fire("action_connect", { uniqueId: props.entry.uniqueId, newTab: false, closeModal: true });
}} }}
onContextMenu={event => { onContextMenu={event => {
event.preventDefault(); event.stopPropagation();
if(selectedItem.remoteValue?.id !== props.entry.uniqueId) { if(selectedItem.remoteValue?.id !== props.entry.uniqueId) {
selectedItem.setValue({ id: props.entry.uniqueId }); selectedItem.setValue({ id: props.entry.uniqueId });
@ -195,9 +195,8 @@ const BookmarkList = React.memo(() => {
<div <div
className={cssStyle.containerBookmarks} className={cssStyle.containerBookmarks}
onContextMenu={event => { onContextMenu={event => {
event.preventDefault();
if(bookmarks.length === 0) { if(bookmarks.length === 0) {
/* We've an extra overlay for not having any bookmarks. */
return; return;
} }

View File

@ -4,6 +4,7 @@ import * as dompurify from "dompurify";
import {ChangeLog, ChangeLogEntry, ChangeSet} from "tc-shared/update/ChangeLog"; import {ChangeLog, ChangeLogEntry, ChangeSet} from "tc-shared/update/ChangeLog";
import {Translatable, VariadicTranslatable} from "tc-shared/ui/react-elements/i18n"; import {Translatable, VariadicTranslatable} from "tc-shared/ui/react-elements/i18n";
import {guid} from "tc-shared/crypto/uid"; import {guid} from "tc-shared/crypto/uid";
import moment from "moment";
const {Remarkable} = require("remarkable"); const {Remarkable} = require("remarkable");
const cssStyle = require("./Renderer.scss"); const cssStyle = require("./Renderer.scss");
@ -108,7 +109,7 @@ export const WhatsNew = (props: { changesUI?: ChangeLog, changesClient?: ChangeL
<VariadicTranslatable key={"info-web"} <VariadicTranslatable key={"info-web"}
text={"The web client has been updated to the version from {}."} text={"The web client has been updated to the version from {}."}
> >
{versionUIDate} {moment(__build.timestamp).format("dd.MM.YY")}
</VariadicTranslatable> </VariadicTranslatable>
); );
} else if (props.changesUI && props.changesClient) { } else if (props.changesUI && props.changesClient) {

View File

@ -29,7 +29,7 @@ export class Checkbox extends React.Component<CheckboxProperties, CheckboxState>
render() { render() {
const disabled = typeof this.state.disabled === "boolean" ? this.state.disabled : this.props.disabled; const disabled = typeof this.state.disabled === "boolean" ? this.state.disabled : this.props.disabled;
const checked = typeof this.props.value === "boolean" ? this.props.value : typeof this.state.checked === "boolean" ? this.state.checked : this.props.initialValue; const checked = (typeof this.props.value === "boolean" ? this.props.value : typeof this.state.checked === "boolean" ? this.state.checked : this.props.initialValue) || false;
const disabledClass = disabled ? cssStyle.disabled : ""; const disabledClass = disabled ? cssStyle.disabled : "";
return ( return (

View File

@ -64,7 +64,7 @@ export const RemoteIconRenderer = React.memo((props: { icon: RemoteIcon | undefi
} }
return ( return (
<IconUrl iconUrl={props.icon.getImageUrl()} title={props.title || ("icon " + props.icon.iconId)} key={"icon-" + props.icon.iconId} /> <IconUrl iconUrl={props.icon.getImageUrl()} title={props.title || ("icon " + props.icon.iconId)} key={"icon-" + props.icon.iconId} className={props.className} />
); );
case "loading": case "loading":