Fixed some bookmark icon related issues
parent
b524fdeb5c
commit
ebc5b178e0
|
@ -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 emoji picker being cut off
|
||||
- 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**
|
||||
- Fixed automated builds
|
||||
|
|
|
@ -2,9 +2,10 @@ import {LogCategory, logError, logWarn} from "tc-shared/log";
|
|||
import {tr, tra} from "tc-shared/i18n/localize";
|
||||
import * as loader 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 {ServerProperties} from "tc-shared/tree/Server";
|
||||
import {Registry} from "tc-events";
|
||||
|
||||
export const kUnknownHistoryServerUniqueId = "unknown";
|
||||
|
||||
|
@ -44,10 +45,17 @@ export type ConnectionHistoryServerInfo = {
|
|||
passwordProtected: boolean
|
||||
}
|
||||
|
||||
export interface ConnectionHistoryEvents {
|
||||
notify_server_info_updated: { serverUniqueId: string, keys: (keyof ConnectionHistoryServerInfo)[] }
|
||||
}
|
||||
|
||||
export class ConnectionHistory {
|
||||
readonly events: Registry<ConnectionHistoryEvents>;
|
||||
private database: IDBDatabase;
|
||||
|
||||
constructor() { }
|
||||
constructor() {
|
||||
this.events = new Registry<ConnectionHistoryEvents>();
|
||||
}
|
||||
|
||||
async initializeDatabase() {
|
||||
const openRequest = indexedDB.open("connection-log", 1);
|
||||
|
@ -306,16 +314,29 @@ export class ConnectionHistory {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
await this.updateDatabaseServerInfo(serverUniqueId, databaseValue => {
|
||||
databaseValue.name = info.name;
|
||||
databaseValue.iconId = info.iconId;
|
||||
const changes: (keyof ConnectionHistoryServerInfo)[] = [];
|
||||
const updateValue = (databaseKey: string, infoKey: keyof ConnectionHistoryServerInfo) => {
|
||||
if(databaseValue[databaseKey] === info[infoKey]) {
|
||||
return;
|
||||
}
|
||||
|
||||
databaseValue.clientsOnline = info.clientsOnline;
|
||||
databaseValue.clientsMax = info.clientsMax;
|
||||
databaseValue[databaseKey] = info[infoKey];
|
||||
changes.push(infoKey);
|
||||
}
|
||||
|
||||
databaseValue.hostBannerUrl = info.hostBannerUrl
|
||||
databaseValue.hostBannerMode = info.hostBannerMode;
|
||||
updateValue("name", "name");
|
||||
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) {
|
||||
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(handler.currentConnectId > 0) {
|
||||
this.history.updateConnectionServerUniqueId(handler.currentConnectId, event.server_properties.virtualserver_unique_identifier)
|
||||
|
@ -573,7 +602,7 @@ class ConnectionHistoryUpdateListener {
|
|||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -581,7 +610,7 @@ export let connectionHistory: ConnectionHistory;
|
|||
let historyInfoListener: ConnectionHistoryUpdateListener;
|
||||
|
||||
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
|
||||
priority: 0,
|
||||
priority: 40,
|
||||
name: "Chat history setup",
|
||||
function: async () => {
|
||||
if(!('indexedDB' in window)) {
|
||||
|
|
|
@ -127,7 +127,7 @@ export class AppController {
|
|||
}
|
||||
|
||||
export let appViewController: AppController;
|
||||
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
|
||||
loader.register_task(Stage.LOADED, {
|
||||
name: "app view",
|
||||
function: async () => {
|
||||
appViewController = new AppController();
|
||||
|
@ -137,5 +137,5 @@ loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
|
|||
(window as any).AppController = AppController;
|
||||
(window as any).appViewController = appViewController;
|
||||
},
|
||||
priority: 0
|
||||
priority: 100
|
||||
});
|
||||
|
|
|
@ -167,16 +167,6 @@ html:root {
|
|||
right: 0;
|
||||
}
|
||||
|
||||
.iconContainer {
|
||||
margin-right: .25em;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.dropdownEntry {
|
||||
position: relative;
|
||||
|
||||
|
@ -305,4 +295,11 @@ html:root {
|
|||
transform: rotate(45deg);
|
||||
-webkit-transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.iconContainer {
|
||||
margin-right: .25em;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
|
@ -23,6 +23,8 @@ import {connectionHistory} from "tc-shared/connectionlog/History";
|
|||
import {RemoteIconInfo} from "tc-shared/file/Icons";
|
||||
import {spawnModalAddCurrentServerToBookmarks} from "tc-shared/ui/modal/bookmarks-add-server/Controller";
|
||||
import {getAudioBackend, OutputDevice} from "tc-shared/audio/Player";
|
||||
import {ignorePromise} from "tc-shared/proto";
|
||||
import {LogCategory, logTrace} from "tc-shared/log";
|
||||
|
||||
class InfoController {
|
||||
private readonly mode: ControlBarMode;
|
||||
|
@ -34,6 +36,8 @@ class InfoController {
|
|||
private handlerRegisteredEvents: (() => void)[] = [];
|
||||
private defaultRecorderListener: () => void;
|
||||
|
||||
private bookmarkServerUniqueIds: string[] = [];
|
||||
|
||||
constructor(events: Registry<ControlBarEvents>, mode: ControlBarMode) {
|
||||
this.events = events;
|
||||
this.mode = mode;
|
||||
|
@ -61,6 +65,16 @@ class InfoController {
|
|||
this.sendVideoState("camera");
|
||||
}));
|
||||
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(getRecorderBackend().getDeviceList().getEvents().on("notify_list_updated", () => this.sendMicrophoneList()));
|
||||
events.push(defaultRecorderEvents.on("notify_default_recorder_changed", () => {
|
||||
|
@ -202,7 +216,9 @@ class InfoController {
|
|||
});
|
||||
}
|
||||
|
||||
/* Note: This method might be executed concurrently */
|
||||
public async sendBookmarks() {
|
||||
this.bookmarkServerUniqueIds = [];
|
||||
const bookmarkList = bookmarks.getOrderedRegisteredBookmarks();
|
||||
|
||||
const parent: Bookmark[] = [];
|
||||
|
@ -216,15 +232,17 @@ class InfoController {
|
|||
let icon: RemoteIconInfo;
|
||||
|
||||
try {
|
||||
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address");
|
||||
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address", true);
|
||||
if(connectInfo) {
|
||||
this.bookmarkServerUniqueIds.push(connectInfo.serverUniqueId);
|
||||
const info = await connectionHistory.queryServerInfo(connectInfo.serverUniqueId);
|
||||
if(info && info.iconId > 0) {
|
||||
icon = { iconId: info.iconId, serverUniqueId: connectInfo.serverUniqueId };
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
/* no need for any error handling */
|
||||
} catch (error) {
|
||||
/* No need to warn in prod build */
|
||||
logTrace(LogCategory.BOOKMARKS, "Failed to query last connect info: %o", error);
|
||||
}
|
||||
|
||||
parentList.push({
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
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 {getIconManager, RemoteIconInfo} from "tc-shared/file/Icons";
|
||||
import {joinClassList} from "tc-shared/ui/react-elements/Helper";
|
||||
|
|
|
@ -11,6 +11,7 @@ import {bookmarks} from "tc-shared/Bookmarks";
|
|||
import {RemoteIconInfo} from "tc-shared/file/Icons";
|
||||
import {connectionHistory} from "tc-shared/connectionlog/History";
|
||||
import {spawnModalAddCurrentServerToBookmarks} from "tc-shared/ui/modal/bookmarks-add-server/Controller";
|
||||
import {LogCategory, logTrace} from "tc-shared/log";
|
||||
|
||||
function renderConnectionItems() {
|
||||
const items: MenuBarEntry[] = [];
|
||||
|
@ -52,7 +53,9 @@ function renderConnectionItems() {
|
|||
return items;
|
||||
}
|
||||
|
||||
let bookmarkServerUniqueIds: string[] = [];
|
||||
async function renderBookmarkItems() {
|
||||
bookmarkServerUniqueIds = [];
|
||||
const bookmarkList = bookmarks.getOrderedRegisteredBookmarks();
|
||||
|
||||
const bookmarkItems: MenuBarEntry[] = [];
|
||||
|
@ -66,15 +69,17 @@ async function renderBookmarkItems() {
|
|||
let icon: RemoteIconInfo;
|
||||
|
||||
try {
|
||||
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address");
|
||||
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address", true);
|
||||
if(connectInfo) {
|
||||
bookmarkServerUniqueIds.push(connectInfo.serverUniqueId);
|
||||
const info = await connectionHistory.queryServerInfo(connectInfo.serverUniqueId);
|
||||
if(info && info.iconId > 0) {
|
||||
icon = { iconId: info.iconId, serverUniqueId: connectInfo.serverUniqueId };
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
/* no need for any error handling */
|
||||
} catch (error) {
|
||||
/* No need to warn in prod build */
|
||||
logTrace(LogCategory.BOOKMARKS, "Failed to query last connect info: %o", error);
|
||||
}
|
||||
|
||||
parentList.push({
|
||||
|
@ -363,6 +368,16 @@ class MenuBarUpdateListener {
|
|||
}));
|
||||
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(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));
|
||||
}
|
||||
|
||||
|
|
|
@ -567,7 +567,7 @@ class BookmarkModalController {
|
|||
}
|
||||
|
||||
return this.bookmarkUniqueServerIds[bookmarkId] = (async () => {
|
||||
const info = await connectionHistory.lastConnectInfo(bookmark.serverAddress, "address");
|
||||
const info = await connectionHistory.lastConnectInfo(bookmark.serverAddress, "address", true);
|
||||
if(!info) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ const BookmarkListEntryRenderer = React.memo((props: { entry: BookmarkListEntry
|
|||
events.fire("action_connect", { uniqueId: props.entry.uniqueId, newTab: false, closeModal: true });
|
||||
}}
|
||||
onContextMenu={event => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if(selectedItem.remoteValue?.id !== props.entry.uniqueId) {
|
||||
selectedItem.setValue({ id: props.entry.uniqueId });
|
||||
|
@ -195,9 +195,8 @@ const BookmarkList = React.memo(() => {
|
|||
<div
|
||||
className={cssStyle.containerBookmarks}
|
||||
onContextMenu={event => {
|
||||
event.preventDefault();
|
||||
|
||||
if(bookmarks.length === 0) {
|
||||
/* We've an extra overlay for not having any bookmarks. */
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import * as dompurify from "dompurify";
|
|||
import {ChangeLog, ChangeLogEntry, ChangeSet} from "tc-shared/update/ChangeLog";
|
||||
import {Translatable, VariadicTranslatable} from "tc-shared/ui/react-elements/i18n";
|
||||
import {guid} from "tc-shared/crypto/uid";
|
||||
import moment from "moment";
|
||||
|
||||
const {Remarkable} = require("remarkable");
|
||||
const cssStyle = require("./Renderer.scss");
|
||||
|
@ -108,7 +109,7 @@ export const WhatsNew = (props: { changesUI?: ChangeLog, changesClient?: ChangeL
|
|||
<VariadicTranslatable key={"info-web"}
|
||||
text={"The web client has been updated to the version from {}."}
|
||||
>
|
||||
{versionUIDate}
|
||||
{moment(__build.timestamp).format("dd.MM.YY")}
|
||||
</VariadicTranslatable>
|
||||
);
|
||||
} else if (props.changesUI && props.changesClient) {
|
||||
|
|
|
@ -29,7 +29,7 @@ export class Checkbox extends React.Component<CheckboxProperties, CheckboxState>
|
|||
|
||||
render() {
|
||||
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 : "";
|
||||
|
||||
return (
|
||||
|
|
|
@ -64,7 +64,7 @@ export const RemoteIconRenderer = React.memo((props: { icon: RemoteIcon | undefi
|
|||
}
|
||||
|
||||
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":
|
||||
|
|
Loading…
Reference in New Issue