mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-07-21 05:04:10 +01:00
[MIRROR] TG-Chat visual limits and fixes (#7580)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> Co-authored-by: Selis <selis@xynolabs.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
/client/verb/export_chat()
|
||||
set category = "OOC"
|
||||
set name = "Export Chatlog"
|
||||
set desc = "Allows to trigger the chat export"
|
||||
|
||||
to_chat(usr, "<span data-command=\"$do_export\"></span>")
|
||||
@@ -1037,7 +1037,7 @@
|
||||
|
||||
//Print notifications/sound if necessary
|
||||
if(!silent && count)
|
||||
owner.visible_message("<font color='green'><b>[owner] [release_verb] everything from their [lowertext(name)]!</b></font>", range = privacy_range)
|
||||
owner.visible_message("<span class='vnotice'><font color='green'><b>[owner] [release_verb] everything from their [lowertext(name)]!</b></font></span>", range = privacy_range)
|
||||
var/soundfile
|
||||
if(!fancy_vore)
|
||||
soundfile = classic_release_sounds[release_sound]
|
||||
@@ -1119,7 +1119,7 @@
|
||||
if(istype(M, /mob/observer)) //CHOMPEdit
|
||||
silent = TRUE
|
||||
if(!silent)
|
||||
owner.visible_message("<font color='green'><b>[owner] [release_verb] [M] from their [lowertext(name)]!</b></font>",range = privacy_range)
|
||||
owner.visible_message("<span class='vnotice'><font color='green'><b>[owner] [release_verb] [M] from their [lowertext(name)]!</b></font></span>",range = privacy_range)
|
||||
var/soundfile
|
||||
if(!fancy_vore)
|
||||
soundfile = classic_release_sounds[release_sound]
|
||||
@@ -1191,7 +1191,7 @@
|
||||
formatted_message = replacetext(formatted_message, "%countprey", living_count)
|
||||
formatted_message = replacetext(formatted_message, "%count", contents.len)
|
||||
|
||||
return("<span class='vwarning'>[formatted_message]</span>")
|
||||
return("<i><font color='red'>[formatted_message]</font></i>")
|
||||
|
||||
/obj/belly/proc/get_examine_msg_absorbed()
|
||||
if(!(contents.len) || !(examine_messages_absorbed.len) || !display_absorbed_examine)
|
||||
@@ -1215,7 +1215,7 @@
|
||||
formatted_message = replacetext(formatted_message, "%prey", english_list(absorbed_victims))
|
||||
formatted_message = replacetext(formatted_message, "%countprey", absorbed_count)
|
||||
|
||||
return("<span class='vwarning'>[formatted_message]</span>")
|
||||
return("<i><font color='red'>[formatted_message]</font></i>")
|
||||
|
||||
// The next function gets the messages set on the belly, in human-readable format.
|
||||
// This is useful in customization boxes and such. The delimiter right now is \n\n so
|
||||
|
||||
@@ -83,12 +83,14 @@ export const Panel = (props, context) => {
|
||||
<ChatPanel lineHeight={settings.lineHeight} />
|
||||
</Pane.Content>
|
||||
<Notifications>
|
||||
{settings.showReconnectWarning && game.connectionLostAt && (
|
||||
<Notifications.Item rightSlot={<ReconnectButton />}>
|
||||
You are either AFK, experiencing lag or the connection has
|
||||
closed.
|
||||
</Notifications.Item>
|
||||
)}
|
||||
{settings.showReconnectWarning &&
|
||||
game.connectionLostAt &&
|
||||
!game.dismissedConnectionWarning && (
|
||||
<Notifications.Item rightSlot={<ReconnectButton />}>
|
||||
You are either AFK, experiencing lag or the connection has
|
||||
closed.
|
||||
</Notifications.Item>
|
||||
)}
|
||||
{settings.showReconnectWarning && game.roundRestartedAt && (
|
||||
<Notifications.Item>
|
||||
The connection has been closed because the server is
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import { useDispatch, useSelector } from 'common/redux';
|
||||
import { Button, Collapsible, Divider, Input, Section, Stack } from 'tgui_ch/components'; // CHOMPEdit - tgui_ch
|
||||
import { removeChatPage, toggleAcceptedType, updateChatPage } from './actions';
|
||||
import { moveChatPageLeft, moveChatPageRight, removeChatPage, toggleAcceptedType, updateChatPage } from './actions';
|
||||
import { MESSAGE_TYPES } from './constants';
|
||||
import { selectCurrentChatPage } from './selectors';
|
||||
|
||||
@@ -30,20 +30,56 @@ export const ChatPageSettings = (props, context) => {
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="times"
|
||||
color="red"
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
removeChatPage({
|
||||
pageId: page.id,
|
||||
})
|
||||
)
|
||||
}>
|
||||
Remove
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
{!page.isMain ? (
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="times"
|
||||
color="red"
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
removeChatPage({
|
||||
pageId: page.id,
|
||||
})
|
||||
)
|
||||
}>
|
||||
Remove
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</Stack>
|
||||
<Divider />
|
||||
<Stack align="center">
|
||||
{!page.isMain ? (
|
||||
<Stack.Item>
|
||||
Reorder Chat: 
|
||||
<Button
|
||||
color="blue"
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
moveChatPageLeft({
|
||||
pageId: page.id,
|
||||
})
|
||||
)
|
||||
}>
|
||||
«
|
||||
</Button>
|
||||
<Button
|
||||
color="blue"
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
moveChatPageRight({
|
||||
pageId: page.id,
|
||||
})
|
||||
)
|
||||
}>
|
||||
»
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</Stack>
|
||||
<Divider />
|
||||
<Section title="Messages to display" level={2}>
|
||||
|
||||
@@ -20,3 +20,5 @@ export const removeChatPage = createAction('chat/removePage');
|
||||
export const changeScrollTracking = createAction('chat/changeScrollTracking');
|
||||
export const saveChatToDisk = createAction('chat/saveToDisk');
|
||||
export const purgeChatMessageArchive = createAction('chat/purgeMessageArchive');
|
||||
export const moveChatPageLeft = createAction('chat/movePageLeft');
|
||||
export const moveChatPageRight = createAction('chat/movePageRight');
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
export const MAX_VISIBLE_MESSAGES = 2500;
|
||||
export const MAX_PERSISTED_MESSAGES = 1000;
|
||||
// export const MAX_VISIBLE_MESSAGES = 2500; No longer a constant
|
||||
// export const MAX_PERSISTED_MESSAGES = 1000; No longer a constant
|
||||
export const MESSAGE_SAVE_INTERVAL = 10000;
|
||||
export const MESSAGE_PRUNE_INTERVAL = 60000;
|
||||
export const COMBINE_MAX_MESSAGES = 5;
|
||||
export const COMBINE_MAX_TIME_WINDOW = 5000;
|
||||
// export const COMBINE_MAX_MESSAGES = 5; No longer a constant
|
||||
// export const COMBINE_MAX_TIME_WINDOW = 5000; No longer a constant
|
||||
export const IMAGE_RETRY_DELAY = 250;
|
||||
export const IMAGE_RETRY_LIMIT = 10;
|
||||
export const IMAGE_RETRY_MESSAGE_AGE = 60000;
|
||||
|
||||
@@ -8,8 +8,8 @@ import DOMPurify from 'dompurify';
|
||||
import { storage } from 'common/storage';
|
||||
import { loadSettings, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from '../settings/actions';
|
||||
import { selectSettings } from '../settings/selectors';
|
||||
import { addChatPage, changeChatPage, changeScrollTracking, loadChat, rebuildChat, removeChatPage, saveChatToDisk, purgeChatMessageArchive, toggleAcceptedType, updateMessageCount } from './actions';
|
||||
import { MAX_PERSISTED_MESSAGES, MESSAGE_SAVE_INTERVAL } from './constants';
|
||||
import { addChatPage, changeChatPage, changeScrollTracking, loadChat, rebuildChat, moveChatPageLeft, moveChatPageRight, removeChatPage, saveChatToDisk, purgeChatMessageArchive, toggleAcceptedType, updateMessageCount } from './actions';
|
||||
import { MESSAGE_SAVE_INTERVAL } from './constants';
|
||||
import { createMessage, serializeMessage } from './model';
|
||||
import { chatRenderer } from './renderer';
|
||||
import { selectChat, selectCurrentChatPage } from './selectors';
|
||||
@@ -19,9 +19,10 @@ const FORBID_TAGS = ['a', 'iframe', 'link', 'video'];
|
||||
|
||||
const saveChatToStorage = async (store) => {
|
||||
const state = selectChat(store.getState());
|
||||
const settings = selectSettings(store.getState());
|
||||
const fromIndex = Math.max(
|
||||
0,
|
||||
chatRenderer.messages.length - MAX_PERSISTED_MESSAGES
|
||||
chatRenderer.messages.length - settings.persistentMessageLimit
|
||||
);
|
||||
const messages = chatRenderer.messages
|
||||
.slice(fromIndex)
|
||||
@@ -61,7 +62,6 @@ const loadChatFromStorage = async (store) => {
|
||||
];
|
||||
chatRenderer.processBatch(batch, {
|
||||
prepend: true,
|
||||
noarchive: true,
|
||||
});
|
||||
}
|
||||
if (archivedMessages) {
|
||||
@@ -116,6 +116,14 @@ export const chatMiddleware = (store) => {
|
||||
}, MESSAGE_SAVE_INTERVAL);
|
||||
return (next) => (action) => {
|
||||
const { type, payload } = action;
|
||||
const settings = selectSettings(store.getState());
|
||||
settings.totalStoredMessages = chatRenderer.getStoredMessages();
|
||||
chatRenderer.setVisualChatLimits(
|
||||
settings.visibleMessageLimit,
|
||||
settings.combineMessageLimit,
|
||||
settings.combineIntervalLimit,
|
||||
settings.logLineCount
|
||||
);
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
loadChatFromStorage(store);
|
||||
@@ -155,7 +163,9 @@ export const chatMiddleware = (store) => {
|
||||
}
|
||||
}
|
||||
|
||||
chatRenderer.processBatch([payload_obj.content]);
|
||||
chatRenderer.processBatch([payload_obj.content], {
|
||||
doArchive: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (type === loadChat.type) {
|
||||
@@ -170,7 +180,9 @@ export const chatMiddleware = (store) => {
|
||||
type === changeChatPage.type ||
|
||||
type === addChatPage.type ||
|
||||
type === removeChatPage.type ||
|
||||
type === toggleAcceptedType.type
|
||||
type === toggleAcceptedType.type ||
|
||||
type === moveChatPageLeft.type ||
|
||||
type === moveChatPageRight.type
|
||||
) {
|
||||
next(action);
|
||||
const page = selectCurrentChatPage(store.getState());
|
||||
@@ -178,7 +190,7 @@ export const chatMiddleware = (store) => {
|
||||
return;
|
||||
}
|
||||
if (type === rebuildChat.type) {
|
||||
chatRenderer.rebuildChat();
|
||||
chatRenderer.rebuildChat(settings.visibleMessages);
|
||||
return next(action);
|
||||
}
|
||||
|
||||
@@ -190,7 +202,6 @@ export const chatMiddleware = (store) => {
|
||||
type === updateHighlightSetting.type
|
||||
) {
|
||||
next(action);
|
||||
const settings = selectSettings(store.getState());
|
||||
chatRenderer.setHighlight(
|
||||
settings.highlightSettings,
|
||||
settings.highlightSettingById
|
||||
@@ -204,7 +215,6 @@ export const chatMiddleware = (store) => {
|
||||
return next(action);
|
||||
}
|
||||
if (type === saveChatToDisk.type) {
|
||||
const settings = selectSettings(store.getState());
|
||||
chatRenderer.saveToDisk(settings.logLineCount);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ export const createPage = (obj) => {
|
||||
}
|
||||
|
||||
return {
|
||||
isMain: false,
|
||||
id: createUuid(),
|
||||
name: 'New Tab',
|
||||
acceptedTypes: acceptedTypes,
|
||||
@@ -33,6 +34,7 @@ export const createMainPage = () => {
|
||||
acceptedTypes[typeDef.type] = true;
|
||||
}
|
||||
return createPage({
|
||||
isMain: true,
|
||||
name: 'Main',
|
||||
acceptedTypes,
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { addChatPage, changeChatPage, loadChat, removeChatPage, toggleAcceptedType, updateChatPage, updateMessageCount, changeScrollTracking } from './actions';
|
||||
import { addChatPage, changeChatPage, loadChat, removeChatPage, moveChatPageLeft, moveChatPageRight, toggleAcceptedType, updateChatPage, updateMessageCount, changeScrollTracking } from './actions';
|
||||
import { canPageAcceptType, createMainPage } from './model';
|
||||
|
||||
const mainPage = createMainPage();
|
||||
@@ -179,5 +179,52 @@ export const chatReducer = (state = initialState, action) => {
|
||||
}
|
||||
return nextState;
|
||||
}
|
||||
if (type === moveChatPageLeft.type) {
|
||||
const { pageId } = payload;
|
||||
const nextState = {
|
||||
...state,
|
||||
pages: [...state.pages],
|
||||
pageById: {
|
||||
...state.pageById,
|
||||
},
|
||||
};
|
||||
const tmpPage = nextState.pageById[pageId];
|
||||
const fromIndex = nextState.pages.indexOf(tmpPage.id);
|
||||
const toIndex = fromIndex - 1;
|
||||
// don't ever move leftmost page
|
||||
if (fromIndex > 0) {
|
||||
// don't ever move anything to the leftmost page
|
||||
if (toIndex > 0) {
|
||||
const tmp = nextState.pages[fromIndex];
|
||||
nextState.pages[fromIndex] = nextState.pages[toIndex];
|
||||
nextState.pages[toIndex] = tmp;
|
||||
}
|
||||
}
|
||||
return nextState;
|
||||
}
|
||||
|
||||
if (type === moveChatPageRight.type) {
|
||||
const { pageId } = payload;
|
||||
const nextState = {
|
||||
...state,
|
||||
pages: [...state.pages],
|
||||
pageById: {
|
||||
...state.pageById,
|
||||
},
|
||||
};
|
||||
const tmpPage = nextState.pageById[pageId];
|
||||
const fromIndex = nextState.pages.indexOf(tmpPage.id);
|
||||
const toIndex = fromIndex + 1;
|
||||
// don't ever move leftmost page
|
||||
if (fromIndex > 0) {
|
||||
// don't ever move anything out of the array
|
||||
if (toIndex < nextState.pages.length) {
|
||||
const tmp = nextState.pages[fromIndex];
|
||||
nextState.pages[fromIndex] = nextState.pages[toIndex];
|
||||
nextState.pages[toIndex] = tmp;
|
||||
}
|
||||
}
|
||||
return nextState;
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { EventEmitter } from 'common/events';
|
||||
import { classes } from 'common/react';
|
||||
import { createLogger } from 'tgui_ch/logging'; // CHOMPEdit - tgui_ch
|
||||
import { COMBINE_MAX_MESSAGES, COMBINE_MAX_TIME_WINDOW, IMAGE_RETRY_DELAY, IMAGE_RETRY_LIMIT, IMAGE_RETRY_MESSAGE_AGE, MAX_PERSISTED_MESSAGES, MAX_VISIBLE_MESSAGES, MESSAGE_PRUNE_INTERVAL, MESSAGE_TYPES, MESSAGE_TYPE_INTERNAL, MESSAGE_TYPE_UNKNOWN } from './constants';
|
||||
import { IMAGE_RETRY_DELAY, IMAGE_RETRY_LIMIT, IMAGE_RETRY_MESSAGE_AGE, MESSAGE_PRUNE_INTERVAL, MESSAGE_TYPES, MESSAGE_TYPE_INTERNAL, MESSAGE_TYPE_UNKNOWN } from './constants';
|
||||
import { render } from 'inferno';
|
||||
import { canPageAcceptType, createMessage, isSameMessage, serializeMessage } from './model';
|
||||
import { highlightNode, linkifyNode } from './replaceInTextNode';
|
||||
@@ -115,6 +115,11 @@ class ChatRenderer {
|
||||
this.visibleMessages = [];
|
||||
this.page = null;
|
||||
this.events = new EventEmitter();
|
||||
// Adjustables
|
||||
this.visibleMessageLimit = 2500;
|
||||
this.combineMessageLimit = 5;
|
||||
this.combineIntervalLimit = 5;
|
||||
this.exportLimit = -1;
|
||||
// Scroll handler
|
||||
/** @type {HTMLElement} */
|
||||
this.scrollNode = null;
|
||||
@@ -160,7 +165,7 @@ class ChatRenderer {
|
||||
this.scrollToBottom();
|
||||
});
|
||||
// Flush the queue
|
||||
this.tryFlushQueue();
|
||||
this.tryFlushQueue(true);
|
||||
}
|
||||
|
||||
onStateLoaded() {
|
||||
@@ -168,9 +173,9 @@ class ChatRenderer {
|
||||
this.tryFlushQueue();
|
||||
}
|
||||
|
||||
tryFlushQueue() {
|
||||
tryFlushQueue(doArchive = false) {
|
||||
if (this.isReady() && this.queue.length > 0) {
|
||||
this.processBatch(this.queue);
|
||||
this.processBatch(this.queue, { doArchive: doArchive });
|
||||
this.queue = [];
|
||||
}
|
||||
}
|
||||
@@ -352,22 +357,33 @@ class ChatRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
setVisualChatLimits(
|
||||
visibleMessageLimit,
|
||||
combineMessageLimit,
|
||||
combineIntervalLimit,
|
||||
exportLimit
|
||||
) {
|
||||
this.visibleMessageLimit = visibleMessageLimit;
|
||||
this.combineMessageLimit = combineMessageLimit;
|
||||
this.combineIntervalLimit = combineIntervalLimit;
|
||||
this.exportLimit = exportLimit;
|
||||
}
|
||||
|
||||
getCombinableMessage(predicate) {
|
||||
const now = Date.now();
|
||||
const len = this.visibleMessages.length;
|
||||
const from = len - 1;
|
||||
const to = Math.max(0, len - COMBINE_MAX_MESSAGES);
|
||||
const to = Math.max(0, len - this.combineMessageLimit);
|
||||
for (let i = from; i >= to; i--) {
|
||||
const message = this.visibleMessages[i];
|
||||
// prettier-ignore
|
||||
const matches = (
|
||||
|
||||
const matches =
|
||||
// Is not an internal message
|
||||
!message.type.startsWith(MESSAGE_TYPE_INTERNAL)
|
||||
!message.type.startsWith(MESSAGE_TYPE_INTERNAL) &&
|
||||
// Text payload must fully match
|
||||
&& isSameMessage(message, predicate)
|
||||
isSameMessage(message, predicate) &&
|
||||
// Must land within the specified time window
|
||||
&& now < message.createdAt + COMBINE_MAX_TIME_WINDOW
|
||||
);
|
||||
now < message.createdAt + this.combineIntervalLimit * 1000;
|
||||
if (matches) {
|
||||
return message;
|
||||
}
|
||||
@@ -376,7 +392,7 @@ class ChatRenderer {
|
||||
}
|
||||
|
||||
processBatch(batch, options = {}) {
|
||||
const { prepend, notifyListeners = true, noArchive = false } = options;
|
||||
const { prepend, notifyListeners = true, doArchive = false } = options;
|
||||
const now = Date.now();
|
||||
// Queue up messages until chat is ready
|
||||
if (!this.isReady()) {
|
||||
@@ -421,6 +437,15 @@ class ChatRenderer {
|
||||
} else {
|
||||
logger.error('Error: message is missing text payload', message);
|
||||
}
|
||||
// Get our commands we might want to send to chat
|
||||
const commands = node.querySelectorAll('[data-command]');
|
||||
if (commands.length) {
|
||||
const command = commands[0].getAttribute('data-command');
|
||||
if (command === '$do_export') {
|
||||
this.saveToDisk(this.exportLimit);
|
||||
}
|
||||
return; // We do not want those logged or shown!
|
||||
}
|
||||
// Get all nodes in this message that want to be rendered like jsx
|
||||
const nodes = node.querySelectorAll('[data-component]');
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
@@ -521,7 +546,7 @@ class ChatRenderer {
|
||||
countByType[message.type] += 1;
|
||||
// TODO: Detect duplicates
|
||||
this.messages.push(message);
|
||||
if (!noArchive) {
|
||||
if (doArchive) {
|
||||
this.archivedMessages.push(serializeMessage(message, true)); // TODO: Actually having a better message archiving maybe for exports?
|
||||
}
|
||||
if (canPageAcceptType(this.page, message.type)) {
|
||||
@@ -559,7 +584,7 @@ class ChatRenderer {
|
||||
// Visible messages
|
||||
{
|
||||
const messages = this.visibleMessages;
|
||||
const fromIndex = Math.max(0, messages.length - MAX_VISIBLE_MESSAGES);
|
||||
const fromIndex = Math.max(0, messages.length - this.visibleMessageLimit);
|
||||
if (fromIndex > 0) {
|
||||
this.visibleMessages = messages.slice(fromIndex);
|
||||
for (let i = 0; i < fromIndex; i++) {
|
||||
@@ -580,7 +605,7 @@ class ChatRenderer {
|
||||
{
|
||||
const fromIndex = Math.max(
|
||||
0,
|
||||
this.messages.length - MAX_PERSISTED_MESSAGES
|
||||
this.messages.length - this.persistentMessageLimit
|
||||
);
|
||||
if (fromIndex > 0) {
|
||||
this.messages = this.messages.slice(fromIndex);
|
||||
@@ -589,15 +614,12 @@ class ChatRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
rebuildChat() {
|
||||
rebuildChat(rebuildLimit) {
|
||||
if (!this.isReady()) {
|
||||
return;
|
||||
}
|
||||
// Make a copy of messages
|
||||
const fromIndex = Math.max(
|
||||
0,
|
||||
this.messages.length - MAX_PERSISTED_MESSAGES
|
||||
);
|
||||
const fromIndex = Math.max(0, this.messages.length - rebuildLimit);
|
||||
const messages = this.messages.slice(fromIndex);
|
||||
// Remove existing nodes
|
||||
for (let message of messages) {
|
||||
@@ -643,10 +665,13 @@ class ChatRenderer {
|
||||
|
||||
// for (let message of this.visibleMessages) { // TODO: Actually having a better message archiving maybe for exports?
|
||||
for (let message of tmpMsgArray) {
|
||||
// Filter messages according to active tab for export
|
||||
if (canPageAcceptType(this.page, message.type)) {
|
||||
messagesHtml += message.html + '\n';
|
||||
}
|
||||
// if (message.node) {
|
||||
// messagesHtml += message.node.outerHTML + '\n';
|
||||
// }
|
||||
messagesHtml += message.html + '\n';
|
||||
}
|
||||
// Create a page
|
||||
// prettier-ignore
|
||||
@@ -675,6 +700,10 @@ class ChatRenderer {
|
||||
purgeMessageArchive() {
|
||||
this.archivedMessages = [];
|
||||
}
|
||||
|
||||
getStoredMessages() {
|
||||
return this.archivedMessages.length;
|
||||
}
|
||||
}
|
||||
|
||||
// Make chat renderer global so that we can continue using the same
|
||||
|
||||
@@ -9,3 +9,4 @@ import { createAction } from 'common/redux';
|
||||
export const roundRestarted = createAction('roundrestart');
|
||||
export const connectionLost = createAction('game/connectionLost');
|
||||
export const connectionRestored = createAction('game/connectionRestored');
|
||||
export const dismissWarning = createAction('game/dismissWarning');
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { connectionLost } from './actions';
|
||||
import { connectionRestored } from './actions';
|
||||
import { connectionRestored, dismissWarning } from './actions';
|
||||
|
||||
const initialState = {
|
||||
// TODO: This is where round info should be.
|
||||
@@ -13,6 +13,7 @@ const initialState = {
|
||||
roundTime: null,
|
||||
roundRestartedAt: null,
|
||||
connectionLostAt: null,
|
||||
dismissedConnectionWarning: false,
|
||||
};
|
||||
|
||||
export const gameReducer = (state = initialState, action) => {
|
||||
@@ -33,6 +34,13 @@ export const gameReducer = (state = initialState, action) => {
|
||||
return {
|
||||
...state,
|
||||
connectionLostAt: null,
|
||||
dismissedConnectionWarning: false,
|
||||
};
|
||||
}
|
||||
if (type === dismissWarning.type) {
|
||||
return {
|
||||
...state,
|
||||
dismissedConnectionWarning: true,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Button } from 'tgui_ch/components'; // CHOMPEdit - tgui_ch
|
||||
import { useDispatch } from 'common/redux';
|
||||
import { dismissWarning } from './game/actions';
|
||||
|
||||
let url: string | null = null;
|
||||
|
||||
@@ -11,10 +13,11 @@ setInterval(() => {
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
export const ReconnectButton = () => {
|
||||
export const ReconnectButton = (props, context) => {
|
||||
if (!url) {
|
||||
return null;
|
||||
}
|
||||
const dispatch = useDispatch(context);
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
@@ -32,6 +35,13 @@ export const ReconnectButton = () => {
|
||||
}}>
|
||||
Relaunch game
|
||||
</Button>
|
||||
<Button
|
||||
color="white"
|
||||
onClick={() => {
|
||||
dispatch(dismissWarning());
|
||||
}}>
|
||||
Dismiss
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -42,6 +42,7 @@ export const SettingsPanel = (props, context) => {
|
||||
</Stack.Item>
|
||||
<Stack.Item grow={1} basis={0}>
|
||||
{activeTab === 'general' && <SettingsGeneral />}
|
||||
{activeTab === 'limits' && <MessageLimits />}
|
||||
{activeTab === 'export' && <ExportTab />}
|
||||
{activeTab === 'chatPage' && <ChatPageSettings />}
|
||||
{activeTab === 'textHighlight' && <TextHighlightSettings />}
|
||||
@@ -169,9 +170,101 @@ export const SettingsGeneral = (props, context) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const MessageLimits = (props, context) => {
|
||||
const dispatch = useDispatch(context);
|
||||
const {
|
||||
visibleMessageLimit,
|
||||
persistentMessageLimit,
|
||||
combineMessageLimit,
|
||||
combineIntervalLimit,
|
||||
} = useSelector(context, selectSettings);
|
||||
return (
|
||||
<Section>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Amount of lines to display 500-10000 (Default: 2500)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={100}
|
||||
stepPixelSize={2}
|
||||
minValue={500}
|
||||
maxValue={10000}
|
||||
value={visibleMessageLimit}
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
visibleMessageLimit: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Amount of visually persistent lines 500-10000 (Default: 1000)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={100}
|
||||
stepPixelSize={2}
|
||||
minValue={500}
|
||||
maxValue={10000}
|
||||
value={persistentMessageLimit}
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
persistentMessageLimit: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Amount of different lines in between to combine 0-10 (Default: 5)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={1}
|
||||
stepPixelSize={10}
|
||||
minValue={0}
|
||||
maxValue={10}
|
||||
value={combineMessageLimit}
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
combineMessageLimit: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Time to combine messages 0-10 (Default: 5 Seconds)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={1}
|
||||
stepPixelSize={10}
|
||||
minValue={0}
|
||||
maxValue={10}
|
||||
value={combineIntervalLimit}
|
||||
unit="s"
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
combineIntervalLimit: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export const ExportTab = (props, context) => {
|
||||
const dispatch = useDispatch(context);
|
||||
const { logRetainDays, logLineCount } = useSelector(context, selectSettings);
|
||||
const { logRetainDays, logLineCount, totalStoredMessages } = useSelector(
|
||||
context,
|
||||
selectSettings
|
||||
);
|
||||
const [purgeConfirm, setPurgeConfirm] = useLocalState(
|
||||
context,
|
||||
'purgeConfirm',
|
||||
@@ -197,11 +290,15 @@ export const ExportTab = (props, context) => {
|
||||
</LabeledList.Item>
|
||||
*/}
|
||||
<LabeledList.Item label="Amount of lines to export (-1 = inf.)">
|
||||
<Input
|
||||
<NumberInput
|
||||
width="5em"
|
||||
monospace
|
||||
step={100}
|
||||
stepPixelSize={2}
|
||||
minValue={-1}
|
||||
maxValue={50000}
|
||||
value={logLineCount}
|
||||
onInput={(e, value) =>
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
logLineCount: value,
|
||||
@@ -210,6 +307,9 @@ export const ExportTab = (props, context) => {
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Totally stored messages">
|
||||
<Box>{totalStoredMessages}</Box>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Divider />
|
||||
<Button icon="save" onClick={() => dispatch(saveChatToDisk())}>
|
||||
|
||||
@@ -9,6 +9,10 @@ export const SETTINGS_TABS = [
|
||||
id: 'general',
|
||||
name: 'General',
|
||||
},
|
||||
{
|
||||
id: 'limits',
|
||||
name: 'Visual Limits',
|
||||
},
|
||||
{
|
||||
id: 'export',
|
||||
name: 'Export',
|
||||
|
||||
@@ -30,6 +30,11 @@ const initialState = {
|
||||
activeTab: SETTINGS_TABS[0].id,
|
||||
},
|
||||
showReconnectWarning: true,
|
||||
visibleMessageLimit: 2500,
|
||||
persistentMessageLimit: 1000,
|
||||
combineMessageLimit: 5,
|
||||
combineIntervalLimit: 5,
|
||||
totalStoredMessages: 0,
|
||||
logRetainDays: -1,
|
||||
logLineCount: -1,
|
||||
};
|
||||
|
||||
@@ -369,6 +369,7 @@ img.icon.bigicon {
|
||||
|
||||
.say,
|
||||
.emote,
|
||||
.emotesubtle,
|
||||
.npcemote,
|
||||
.infoplain,
|
||||
.oocplain,
|
||||
|
||||
@@ -387,6 +387,7 @@ img.icon.bigicon {
|
||||
|
||||
.say,
|
||||
.emote,
|
||||
.emotesubtle,
|
||||
.npcemote,
|
||||
.infoplain,
|
||||
.oocplain,
|
||||
|
||||
@@ -369,6 +369,7 @@ img.icon.bigicon {
|
||||
|
||||
.say,
|
||||
.emote,
|
||||
.emotesubtle,
|
||||
.npcemote,
|
||||
.infoplain,
|
||||
.oocplain,
|
||||
|
||||
@@ -387,6 +387,7 @@ img.icon.bigicon {
|
||||
|
||||
.say,
|
||||
.emote,
|
||||
.emotesubtle,
|
||||
.npcemote,
|
||||
.infoplain,
|
||||
.oocplain,
|
||||
|
||||
File diff suppressed because one or more lines are too long
+126
-126
File diff suppressed because one or more lines are too long
@@ -4297,6 +4297,7 @@
|
||||
#include "code\modules\telesci\telesci_computer.dm"
|
||||
#include "code\modules\tension\tension.dm"
|
||||
#include "code\modules\tgchat\_legacy.dm"
|
||||
#include "code\modules\tgchat\chat_verbs.dm"
|
||||
#include "code\modules\tgchat\message.dm"
|
||||
#include "code\modules\tgchat\to_chat.dm"
|
||||
#include "code\modules\tgs\includes.dm"
|
||||
|
||||
Reference in New Issue
Block a user