mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
[MIRROR] TG-Chat log limits (#7719)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> Co-authored-by: Selis <selis@xynolabs.com>
This commit is contained in:
@@ -201,13 +201,13 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
MessageNoRecipient(parsed_message)
|
||||
send2adminchat() //VOREStation Add
|
||||
//show it to the person adminhelping too
|
||||
to_chat(C, "<span class='adminnotice'>PM to-<b>Admins</b>: [name]</span>")
|
||||
to_chat(C, "<span class='pm adminnotice'>PM to-<b>Admins</b>: [name]</span>")
|
||||
|
||||
//send it to irc if nobody is on and tell us how many were on
|
||||
var/admin_number_present = send2irc_adminless_only(initiator_ckey, name)
|
||||
log_admin("Ticket #[id]: [key_name(initiator)]: [name] - heard by [admin_number_present] non-AFK admins who have +BAN.")
|
||||
if(admin_number_present <= 0)
|
||||
to_chat(C, "<span class='notice'>No active admins are online, your adminhelp was sent to the admin discord.</span>") //VOREStation Edit
|
||||
to_chat(C, "<span class='pm notice'>No active admins are online, your adminhelp was sent to the admin discord.</span>") //VOREStation Edit
|
||||
send2adminchat() //VOREStation Add
|
||||
//YW EDIT START
|
||||
var/list/adm = get_admin_counts()
|
||||
@@ -280,7 +280,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
//won't bug irc
|
||||
/datum/admin_help/proc/MessageNoRecipient(msg)
|
||||
var/ref_src = "\ref[src]"
|
||||
var/chat_msg = "<span class='adminnotice'><span class='adminhelp'>Ticket [TicketHref("#[id]", ref_src)]</span><b>: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]:</b> [msg]</span>"
|
||||
var/chat_msg = "<span class='pm adminnotice'><span class='adminhelp'>Ticket [TicketHref("#[id]", ref_src)]</span><b>: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]:</b> [msg]</span>"
|
||||
|
||||
AddInteraction("<font color='red'>[LinkedReplyName(ref_src)]: [msg]</font>")
|
||||
//send this msg to all admins
|
||||
@@ -652,7 +652,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
if(tgui_alert(usr, "You already have a ticket open. Is this for the same issue?","Duplicate?",list("Yes","No")) != "No")
|
||||
if(current_ticket)
|
||||
current_ticket.MessageNoRecipient(msg)
|
||||
to_chat(usr, "<span class='adminnotice'>PM to-<b>Admins</b>: [msg]</span>")
|
||||
to_chat(usr, "<span class='pm adminnotice'>PM to-<b>Admins</b>: [msg]</span>")
|
||||
return
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Ticket not found, creating new one...</span>")
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
to_chat(M, "<B>You hear a voice in your head...</B> <i>[msg]</i>")
|
||||
|
||||
log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]")
|
||||
msg = "<span class='adminnotice'><b> SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] :</b> [msg]</span>"
|
||||
msg = "<span class='pm adminnotice'><b> SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] :</b> [msg]</span>"
|
||||
message_admins(msg)
|
||||
admin_ticket_log(M, msg)
|
||||
feedback_add_details("admin_verb","SMS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
@@ -148,7 +148,7 @@
|
||||
|
||||
to_chat(M, msg)
|
||||
log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]")
|
||||
msg = "<span class='adminnotice'><b> DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]):</b> [msg]<BR></span>"
|
||||
msg = "<span class='pm adminnotice'><b> DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]):</b> [msg]<BR></span>"
|
||||
message_admins(msg)
|
||||
admin_ticket_log(M, msg)
|
||||
feedback_add_details("admin_verb","DIRN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -63,10 +63,8 @@
|
||||
new_mob.key = picked_client.key //Finally put them in the mob
|
||||
if(organs)
|
||||
new_mob.copy_from_prefs_vr()
|
||||
// CHOMPEdit Start
|
||||
if(LAZYLEN(new_mob.vore_organs))
|
||||
new_mob.vore_selected = new_mob.vore_organs[1]
|
||||
// CHOMPEdit End
|
||||
|
||||
log_admin("[key_name_admin(src)] has spawned [new_mob.key] as mob [new_mob.type].")
|
||||
message_admins("[key_name_admin(src)] has spawned [new_mob.key] as mob [new_mob.type].", 1)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
// 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_SAVE_INTERVAL = 10000; No longer a constant
|
||||
export const MESSAGE_PRUNE_INTERVAL = 60000;
|
||||
// export const COMBINE_MAX_MESSAGES = 5; No longer a constant
|
||||
// export const COMBINE_MAX_TIME_WINDOW = 5000; No longer a constant
|
||||
@@ -61,7 +61,7 @@ export const MESSAGE_TYPES = [
|
||||
type: MESSAGE_TYPE_NPCEMOTE, // Needs to be first
|
||||
name: 'NPC Emotes / Says',
|
||||
description: 'In-character emotes and says from NPCs',
|
||||
selector: '.npcemote, .npcsay',
|
||||
selector: '.npcemote, .npcsay :not(.radio)',
|
||||
},
|
||||
{
|
||||
type: MESSAGE_TYPE_LOCALCHAT,
|
||||
@@ -99,7 +99,7 @@ export const MESSAGE_TYPES = [
|
||||
name: 'Info',
|
||||
description: 'Non-urgent messages from the game and items',
|
||||
selector:
|
||||
'.notice:not(.pm), .adminnotice, .info, .sinister, .cult, .infoplain, .announce, .hear, .smallnotice, .holoparasite, .boldnotice',
|
||||
'.notice:not(.pm), .adminnotice:not(.pm), .info, .sinister, .cult, .infoplain, .announce, .hear, .smallnotice, .holoparasite, .boldnotice',
|
||||
},
|
||||
{
|
||||
type: MESSAGE_TYPE_WARNING,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { storage } from 'common/storage';
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
import { selectGame } from '../game/selectors';
|
||||
import {
|
||||
addHighlightSetting,
|
||||
loadSettings,
|
||||
@@ -29,13 +30,14 @@ import {
|
||||
toggleAcceptedType,
|
||||
updateMessageCount,
|
||||
} from './actions';
|
||||
import { MESSAGE_SAVE_INTERVAL } from './constants';
|
||||
import { createMessage, serializeMessage } from './model';
|
||||
import { chatRenderer } from './renderer';
|
||||
import { selectChat, selectCurrentChatPage } from './selectors';
|
||||
|
||||
// List of blacklisted tags
|
||||
const FORBID_TAGS = ['a', 'iframe', 'link', 'video'];
|
||||
let storedRounds = [];
|
||||
let storedLines = [];
|
||||
|
||||
const saveChatToStorage = async (store) => {
|
||||
const state = selectChat(store.getState());
|
||||
@@ -85,32 +87,49 @@ const loadChatFromStorage = async (store) => {
|
||||
});
|
||||
}
|
||||
if (archivedMessages) {
|
||||
chatRenderer.archivedMessages = archivedMessages;
|
||||
|
||||
/* FIXME Implement this later on
|
||||
for (let archivedMessage of archivedMessages) {
|
||||
if (archivedMessage.html) {
|
||||
archivedMessage.html = DOMPurify.sanitize(archivedMessage.html, {
|
||||
FORBID_TAGS,
|
||||
});
|
||||
}
|
||||
}
|
||||
const settings = selectSettings(store.getState());
|
||||
const filteredMessages = [];
|
||||
|
||||
// Checks if the setting is actually set or set to -1 (infinite)
|
||||
// Otherwise make it grow infinitely
|
||||
if (settings.logRetainDays || settings.logRetainDays === -1) {
|
||||
const limit = new Date();
|
||||
limit.setDate(limit.getMinutes() - settings.logRetainDays);
|
||||
if (settings.logRetainRounds) {
|
||||
storedRounds = [];
|
||||
storedLines = [];
|
||||
let oldId = null;
|
||||
let currentLine = 0;
|
||||
settings.storedRounds = 0;
|
||||
settings.exportStart = 0;
|
||||
settings.exportEnd = 0;
|
||||
|
||||
for (let message of archivedMessages) {
|
||||
const timestamp = new Date(message.createdAt);
|
||||
timestamp.setDate(timestamp.getMinutes() - settings.logRetainDays);
|
||||
|
||||
if (timestamp.getDate() < limit.getDate()) {
|
||||
filteredMessages.push(message);
|
||||
const currentId = message.roundId;
|
||||
if (currentId !== oldId) {
|
||||
const round = currentId;
|
||||
const line = currentLine;
|
||||
storedRounds.push(round);
|
||||
storedLines.push(line);
|
||||
oldId = currentId;
|
||||
currentLine++;
|
||||
}
|
||||
}
|
||||
|
||||
archivedMessages.length = 0;
|
||||
if (storedRounds.length > settings.logRetainRounds) {
|
||||
chatRenderer.archivedMessages = archivedMessages.slice(
|
||||
storedLines[storedRounds.length - settings.logRetainRounds],
|
||||
);
|
||||
settings.storedRounds = settings.logRetainRounds;
|
||||
} else {
|
||||
chatRenderer.archivedMessages = archivedMessages;
|
||||
}
|
||||
settings.lastId = oldId;
|
||||
} else {
|
||||
chatRenderer.archivedMessages = archivedMessages;
|
||||
}
|
||||
|
||||
chatRenderer.archivedMessages = filteredMessages;
|
||||
*/
|
||||
}
|
||||
store.dispatch(loadChat(state));
|
||||
};
|
||||
@@ -131,21 +150,28 @@ export const chatMiddleware = (store) => {
|
||||
chatRenderer.events.on('scrollTrackingChanged', (scrollTracking) => {
|
||||
store.dispatch(changeScrollTracking(scrollTracking));
|
||||
});
|
||||
setInterval(() => {
|
||||
saveChatToStorage(store);
|
||||
}, MESSAGE_SAVE_INTERVAL);
|
||||
return (next) => (action) => {
|
||||
const { type, payload } = action;
|
||||
const settings = selectSettings(store.getState());
|
||||
const game = selectGame(store.getState());
|
||||
settings.totalStoredMessages = chatRenderer.getStoredMessages();
|
||||
settings.storedRounds = storedRounds.length;
|
||||
chatRenderer.setVisualChatLimits(
|
||||
settings.visibleMessageLimit,
|
||||
settings.combineMessageLimit,
|
||||
settings.combineIntervalLimit,
|
||||
settings.logLineCount,
|
||||
settings.logEnable,
|
||||
settings.logLimit,
|
||||
settings.storedTypes,
|
||||
game.roundId,
|
||||
);
|
||||
if (!initialized) {
|
||||
// Load the chat once settings are loaded
|
||||
if (!initialized && settings.initialized) {
|
||||
initialized = true;
|
||||
setInterval(() => {
|
||||
saveChatToStorage(store);
|
||||
}, settings.saveInterval * 1000);
|
||||
loadChatFromStorage(store);
|
||||
}
|
||||
if (type === 'chat/message') {
|
||||
@@ -186,6 +212,11 @@ export const chatMiddleware = (store) => {
|
||||
chatRenderer.processBatch([payload_obj.content], {
|
||||
doArchive: true,
|
||||
});
|
||||
if (game.roundId !== settings.lastId) {
|
||||
storedRounds.push(game.roundId);
|
||||
storedLines.push(settings.totalStoredMessages - 1);
|
||||
settings.lastId = game.roundId;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (type === loadChat.type) {
|
||||
@@ -235,11 +266,21 @@ export const chatMiddleware = (store) => {
|
||||
return next(action);
|
||||
}
|
||||
if (type === saveChatToDisk.type) {
|
||||
chatRenderer.saveToDisk(settings.logLineCount);
|
||||
chatRenderer.saveToDisk(
|
||||
settings.logLineCount,
|
||||
storedLines[storedLines.length - settings.exportEnd],
|
||||
storedLines[storedLines.length - settings.exportStart],
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (type === purgeChatMessageArchive.type) {
|
||||
chatRenderer.purgeMessageArchive();
|
||||
storedRounds = [];
|
||||
storedLines = [];
|
||||
settings.lastId = null;
|
||||
settings.storedRounds = 0;
|
||||
settings.exportStart = 0;
|
||||
settings.exportEnd = 0;
|
||||
return;
|
||||
}
|
||||
return next(action);
|
||||
|
||||
@@ -11,6 +11,8 @@ import { MESSAGE_TYPE_INTERNAL, MESSAGE_TYPES } from './constants';
|
||||
export const canPageAcceptType = (page, type) =>
|
||||
type.startsWith(MESSAGE_TYPE_INTERNAL) || page.acceptedTypes[type];
|
||||
|
||||
export const canStoreType = (storedTypes, type) => storedTypes[type];
|
||||
|
||||
export const createPage = (obj) => {
|
||||
let acceptedTypes = {};
|
||||
|
||||
@@ -43,6 +45,7 @@ export const createMainPage = () => {
|
||||
|
||||
export const createMessage = (payload) => ({
|
||||
createdAt: Date.now(),
|
||||
roundId: null,
|
||||
...payload,
|
||||
});
|
||||
|
||||
@@ -52,6 +55,7 @@ export const serializeMessage = (message, archive = false) => ({
|
||||
html: archive ? message.node.outerHTML : message.html,
|
||||
times: message.times,
|
||||
createdAt: message.createdAt,
|
||||
roundId: message.roundId,
|
||||
});
|
||||
|
||||
export const isSameMessage = (a, b) =>
|
||||
|
||||
@@ -6,25 +6,27 @@
|
||||
|
||||
import { EventEmitter } from 'common/events';
|
||||
import { classes } from 'common/react';
|
||||
import { render } from 'react-dom';
|
||||
import { createLogger } from 'tgui/logging';
|
||||
|
||||
import { Tooltip } from '../../tgui/components';
|
||||
import {
|
||||
IMAGE_RETRY_DELAY,
|
||||
IMAGE_RETRY_LIMIT,
|
||||
IMAGE_RETRY_MESSAGE_AGE,
|
||||
MESSAGE_PRUNE_INTERVAL,
|
||||
MESSAGE_TYPES,
|
||||
MESSAGE_TYPE_INTERNAL,
|
||||
MESSAGE_TYPE_UNKNOWN,
|
||||
MESSAGE_TYPES,
|
||||
} from './constants';
|
||||
import { render } from 'react-dom';
|
||||
import {
|
||||
canPageAcceptType,
|
||||
canStoreType,
|
||||
createMessage,
|
||||
isSameMessage,
|
||||
serializeMessage,
|
||||
} from './model';
|
||||
import { highlightNode, linkifyNode } from './replaceInTextNode';
|
||||
import { Tooltip } from '../../tgui/components';
|
||||
|
||||
const logger = createLogger('chatRenderer');
|
||||
|
||||
@@ -132,7 +134,11 @@ class ChatRenderer {
|
||||
this.visibleMessageLimit = 2500;
|
||||
this.combineMessageLimit = 5;
|
||||
this.combineIntervalLimit = 5;
|
||||
this.exportLimit = -1;
|
||||
this.exportLimit = 0;
|
||||
this.logLimit = 0;
|
||||
this.logEnable = true;
|
||||
this.roundId = null;
|
||||
this.storedTypes = {};
|
||||
// Scroll handler
|
||||
/** @type {HTMLElement} */
|
||||
this.scrollNode = null;
|
||||
@@ -375,11 +381,19 @@ class ChatRenderer {
|
||||
combineMessageLimit,
|
||||
combineIntervalLimit,
|
||||
exportLimit,
|
||||
logEnable,
|
||||
logLimit,
|
||||
storedTypes,
|
||||
roundId,
|
||||
) {
|
||||
this.visibleMessageLimit = visibleMessageLimit;
|
||||
this.combineMessageLimit = combineMessageLimit;
|
||||
this.combineIntervalLimit = combineIntervalLimit;
|
||||
this.exportLimit = exportLimit;
|
||||
this.logEnable = logEnable;
|
||||
this.logLimit = logLimit;
|
||||
this.storedTypes = storedTypes;
|
||||
this.roundId = roundId;
|
||||
}
|
||||
|
||||
getCombinableMessage(predicate) {
|
||||
@@ -561,7 +575,26 @@ class ChatRenderer {
|
||||
countByType[message.type] += 1;
|
||||
// TODO: Detect duplicates
|
||||
this.messages.push(message);
|
||||
if (doArchive) {
|
||||
if (
|
||||
doArchive &&
|
||||
this.logEnable &&
|
||||
this.storedTypes &&
|
||||
canStoreType(this.storedTypes, message.type)
|
||||
) {
|
||||
message.roundId = this.roundId;
|
||||
if (
|
||||
this.logLimit > 0 &&
|
||||
this.archivedMessages.length >= this.logLimit + 1
|
||||
) {
|
||||
this.archivedMessages = this.archivedMessages.slice(
|
||||
-(this.logLimit - 1),
|
||||
);
|
||||
} else if (
|
||||
this.logLimit > 0 &&
|
||||
this.archivedMessages.length >= this.logLimit
|
||||
) {
|
||||
this.archivedMessages.shift();
|
||||
}
|
||||
this.archivedMessages.push(serializeMessage(message, true)); // TODO: Actually having a better message archiving maybe for exports?
|
||||
}
|
||||
if (canPageAcceptType(this.page, message.type)) {
|
||||
@@ -650,7 +683,7 @@ class ChatRenderer {
|
||||
});
|
||||
}
|
||||
|
||||
saveToDisk(logLineCount) {
|
||||
saveToDisk(logLineCount, startLine = 0, endLine = 0) {
|
||||
// Allow only on IE11
|
||||
if (Byond.IS_LTE_IE10) {
|
||||
return;
|
||||
@@ -672,7 +705,16 @@ class ChatRenderer {
|
||||
let messagesHtml = '';
|
||||
|
||||
let tmpMsgArray = [];
|
||||
if (logLineCount > 0) {
|
||||
if (startLine || endLine) {
|
||||
if (!endLine) {
|
||||
tmpMsgArray = this.archivedMessages.slice(startLine);
|
||||
} else {
|
||||
tmpMsgArray = this.archivedMessages.slice(startLine, endLine);
|
||||
}
|
||||
if (logLineCount > 0) {
|
||||
tmpMsgArray = tmpMsgArray.slice(-logLineCount);
|
||||
}
|
||||
} else if (logLineCount > 0) {
|
||||
tmpMsgArray = this.archivedMessages.slice(-logLineCount);
|
||||
} else {
|
||||
tmpMsgArray = this.archivedMessages;
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useDispatch, useSelector } from 'tgui/backend';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Collapsible,
|
||||
ColorBox,
|
||||
Divider,
|
||||
Dropdown,
|
||||
@@ -22,26 +23,30 @@ import {
|
||||
Tabs,
|
||||
TextArea,
|
||||
} from 'tgui/components';
|
||||
|
||||
import { ChatPageSettings } from '../chat';
|
||||
import {
|
||||
purgeChatMessageArchive,
|
||||
rebuildChat,
|
||||
saveChatToDisk,
|
||||
purgeChatMessageArchive,
|
||||
} from '../chat/actions';
|
||||
import { MESSAGE_TYPES } from '../chat/constants';
|
||||
import { useGame } from '../game';
|
||||
import { THEMES } from '../themes';
|
||||
import {
|
||||
changeSettingsTab,
|
||||
updateSettings,
|
||||
addHighlightSetting,
|
||||
changeSettingsTab,
|
||||
removeHighlightSetting,
|
||||
updateHighlightSetting,
|
||||
updateSettings,
|
||||
updateToggle,
|
||||
} from './actions';
|
||||
import { SETTINGS_TABS, FONTS, MAX_HIGHLIGHT_SETTINGS } from './constants';
|
||||
import { FONTS, MAX_HIGHLIGHT_SETTINGS, SETTINGS_TABS } from './constants';
|
||||
import {
|
||||
selectActiveTab,
|
||||
selectSettings,
|
||||
selectHighlightSettings,
|
||||
selectHighlightSettingById,
|
||||
selectHighlightSettings,
|
||||
selectSettings,
|
||||
} from './selectors';
|
||||
|
||||
export const SettingsPanel = (props) => {
|
||||
@@ -207,6 +212,7 @@ export const MessageLimits = (props) => {
|
||||
persistentMessageLimit,
|
||||
combineMessageLimit,
|
||||
combineIntervalLimit,
|
||||
saveInterval,
|
||||
} = useSelector(selectSettings);
|
||||
return (
|
||||
<Section>
|
||||
@@ -228,13 +234,21 @@ export const MessageLimits = (props) => {
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
{visibleMessageLimit >= 5000 ? (
|
||||
<Box inline fontSize="0.9em" color="red">
|
||||
Impacts performance!
|
||||
</Box>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Amount of visually persistent lines 500-10000 (Default: 1000)">
|
||||
<LabeledList.Item label="Amount of visually persistent lines 0-10000 (Default: 1000)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={100}
|
||||
stepPixelSize={2}
|
||||
minValue={500}
|
||||
minValue={0}
|
||||
maxValue={10000}
|
||||
value={persistentMessageLimit}
|
||||
format={(value) => toFixed(value)}
|
||||
@@ -246,8 +260,16 @@ export const MessageLimits = (props) => {
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
{persistentMessageLimit >= 2500 ? (
|
||||
<Box inline fontSize="0.9em" color="red">
|
||||
Delays initialization!
|
||||
</Box>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Amount of different lines in between to combine 0-10 (Default: 5)">
|
||||
<LabeledList.Item label="Amount of different lines in-between to combine 0-10 (Default: 5)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={1}
|
||||
@@ -284,6 +306,33 @@ export const MessageLimits = (props) => {
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Message store interval 1-10 (Default: 10 Seconds) [Requires restart]">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={1}
|
||||
stepPixelSize={5}
|
||||
minValue={1}
|
||||
maxValue={10}
|
||||
value={saveInterval}
|
||||
unit="s"
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
saveInterval: value,
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
{saveInterval <= 3 ? (
|
||||
<Box inline fontSize="0.9em" color="red">
|
||||
Warning, experimental! Might crash!
|
||||
</Box>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
@@ -291,34 +340,205 @@ export const MessageLimits = (props) => {
|
||||
|
||||
export const ExportTab = (props) => {
|
||||
const dispatch = useDispatch();
|
||||
const { logRetainDays, logLineCount, totalStoredMessages } =
|
||||
useSelector(selectSettings);
|
||||
const game = useGame();
|
||||
const {
|
||||
storedRounds,
|
||||
exportStart,
|
||||
exportEnd,
|
||||
logRetainRounds,
|
||||
logEnable,
|
||||
logLineCount,
|
||||
logLimit,
|
||||
totalStoredMessages,
|
||||
storedTypes,
|
||||
} = useSelector(selectSettings);
|
||||
const [purgeConfirm, setPurgeConfirm] = useLocalState('purgeConfirm', 0);
|
||||
const [logConfirm, setLogConfirm] = useLocalState('logConfirm', 0);
|
||||
return (
|
||||
<Section>
|
||||
<LabeledList>
|
||||
{/* FIXME: Implement this later on
|
||||
<LabeledList.Item label="Days to retain logs (-1 = inf.)">
|
||||
<Input
|
||||
width="5em"
|
||||
monospace
|
||||
value={logRetainDays}
|
||||
onInput={(e, value) =>
|
||||
<Flex align="baseline">
|
||||
{logEnable ? (
|
||||
logConfirm ? (
|
||||
<Button
|
||||
icon="ban"
|
||||
color="red"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
updateSettings({
|
||||
logEnable: false,
|
||||
}),
|
||||
);
|
||||
setLogConfirm(false);
|
||||
}}
|
||||
>
|
||||
Disable?
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
icon="ban"
|
||||
color="red"
|
||||
onClick={() => {
|
||||
setLogConfirm(true);
|
||||
setTimeout(() => {
|
||||
setLogConfirm(false);
|
||||
}, 5000);
|
||||
}}
|
||||
>
|
||||
Disable logging
|
||||
</Button>
|
||||
)
|
||||
) : (
|
||||
<Button
|
||||
icon="download"
|
||||
color="green"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
updateSettings({
|
||||
logRetainDays: value,
|
||||
})
|
||||
logEnable: true,
|
||||
}),
|
||||
);
|
||||
}}
|
||||
>
|
||||
Enable logging
|
||||
</Button>
|
||||
)}
|
||||
<Flex.Item grow={1} />
|
||||
<Flex.Item color="label">Round ID: </Flex.Item>
|
||||
<Flex.Item color={game.roundId ? '' : 'red'}>
|
||||
{game.roundId ? game.roundId : 'ERROR'}
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
{logEnable ? (
|
||||
<>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Amount of rounds to log (1 to 8)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={1}
|
||||
stepPixelSize={10}
|
||||
minValue={1}
|
||||
maxValue={8}
|
||||
value={logRetainRounds}
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
logRetainRounds: value,
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
{logRetainRounds > 3 ? (
|
||||
<Box inline fontSize="0.9em" color="red">
|
||||
Warning, might crash!
|
||||
</Box>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Hardlimit for the log archive (0 = inf. to 50000)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={500}
|
||||
stepPixelSize={10}
|
||||
minValue={0}
|
||||
maxValue={50000}
|
||||
value={logLimit}
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
logLimit: value,
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
{logLimit > 0 ? (
|
||||
<Box
|
||||
inline
|
||||
fontSize="0.9em"
|
||||
color={logLimit > 10000 ? 'red' : 'label'}
|
||||
>
|
||||
{logLimit > 15000
|
||||
? 'Warning, might crash! Takes priority above round retention.'
|
||||
: 'Takes priority above round retention.'}
|
||||
</Box>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Section>
|
||||
<Collapsible mt={1} color="transparent" title="Messages to log">
|
||||
{MESSAGE_TYPES.map((typeDef) => (
|
||||
<Button.Checkbox
|
||||
key={typeDef.type}
|
||||
checked={storedTypes[typeDef.type]}
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
updateToggle({
|
||||
type: typeDef.type,
|
||||
}),
|
||||
)
|
||||
}
|
||||
>
|
||||
{typeDef.name}
|
||||
</Button.Checkbox>
|
||||
))}
|
||||
</Collapsible>
|
||||
</Section>
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Export round start (0 = curr.) / end (0 = dis.)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={1}
|
||||
stepPixelSize={10}
|
||||
minValue={0}
|
||||
maxValue={exportEnd === 0 ? 0 : exportEnd - 1}
|
||||
value={exportStart}
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
exportStart: value,
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={1}
|
||||
stepPixelSize={10}
|
||||
minValue={exportStart === 0 ? 0 : exportStart + 1}
|
||||
maxValue={storedRounds}
|
||||
value={exportEnd}
|
||||
format={(value) => toFixed(value)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
exportEnd: value,
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<Box inline fontSize="0.9em" color="label">
|
||||
Stored Rounds:
|
||||
</Box>
|
||||
<Box inline>{storedRounds}</Box>
|
||||
</LabeledList.Item>
|
||||
*/}
|
||||
<LabeledList.Item label="Amount of lines to export (-1 = inf.)">
|
||||
<LabeledList.Item label="Amount of lines to export (0 = inf.)">
|
||||
<NumberInput
|
||||
width="5em"
|
||||
step={100}
|
||||
stepPixelSize={2}
|
||||
minValue={-1}
|
||||
stepPixelSize={10}
|
||||
minValue={0}
|
||||
maxValue={50000}
|
||||
value={logLineCount}
|
||||
format={(value) => toFixed(value)}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { createAction } from 'common/redux';
|
||||
|
||||
import { createHighlightSetting } from './model';
|
||||
|
||||
export const updateToggle = createAction('settings/updateToggle');
|
||||
export const updateSettings = createAction('settings/update');
|
||||
export const loadSettings = createAction('settings/load');
|
||||
export const changeSettingsTab = createAction('settings/changeTab');
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
removeHighlightSetting,
|
||||
updateHighlightSetting,
|
||||
updateSettings,
|
||||
updateToggle,
|
||||
} from './actions';
|
||||
import { FONTS_DISABLED } from './constants';
|
||||
import { selectSettings } from './selectors';
|
||||
@@ -63,6 +64,7 @@ export const settingsMiddleware = (store) => {
|
||||
});
|
||||
}
|
||||
if (
|
||||
type === updateToggle.type ||
|
||||
type === updateSettings.type ||
|
||||
type === loadSettings.type ||
|
||||
type === addHighlightSetting.type ||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { MESSAGE_TYPES } from '../chat/constants';
|
||||
import {
|
||||
addHighlightSetting,
|
||||
changeSettingsTab,
|
||||
@@ -13,6 +14,7 @@ import {
|
||||
toggleSettings,
|
||||
updateHighlightSetting,
|
||||
updateSettings,
|
||||
updateToggle,
|
||||
} from './actions';
|
||||
import { FONTS, MAX_HIGHLIGHT_SETTINGS, SETTINGS_TABS } from './constants';
|
||||
import { createDefaultHighlightSetting } from './model';
|
||||
@@ -41,11 +43,20 @@ const initialState = {
|
||||
showReconnectWarning: true,
|
||||
visibleMessageLimit: 2500,
|
||||
persistentMessageLimit: 1000,
|
||||
saveInterval: 10,
|
||||
combineMessageLimit: 5,
|
||||
combineIntervalLimit: 5,
|
||||
totalStoredMessages: 0,
|
||||
logRetainDays: -1,
|
||||
logLineCount: -1,
|
||||
logRetainRounds: 2,
|
||||
logEnable: true,
|
||||
logLineCount: 0,
|
||||
logLimit: 10000,
|
||||
storedRounds: 0,
|
||||
exportStart: 0,
|
||||
exportEnd: 0,
|
||||
lastId: null,
|
||||
initialized: false,
|
||||
storedTypes: {},
|
||||
};
|
||||
|
||||
export const settingsReducer = (state = initialState, action) => {
|
||||
@@ -56,6 +67,14 @@ export const settingsReducer = (state = initialState, action) => {
|
||||
...payload,
|
||||
};
|
||||
}
|
||||
if (type === updateToggle.type) {
|
||||
const { type } = payload;
|
||||
state.storedTypes[type] = !state.storedTypes[type];
|
||||
return {
|
||||
...state,
|
||||
storedTypes: { ...state.storedTypes },
|
||||
};
|
||||
}
|
||||
if (type === loadSettings.type) {
|
||||
// Validate version and/or migrate state
|
||||
if (!payload?.version) {
|
||||
@@ -67,6 +86,17 @@ export const settingsReducer = (state = initialState, action) => {
|
||||
...state,
|
||||
...payload,
|
||||
};
|
||||
nextState.initialized = true;
|
||||
let newFilters = {};
|
||||
for (let typeDef of MESSAGE_TYPES) {
|
||||
// alert(typeDef.type);
|
||||
if (nextState.storedTypes[typeDef.type] === null) {
|
||||
newFilters[typeDef.type] = true;
|
||||
} else {
|
||||
newFilters[typeDef.type] = nextState.storedTypes[typeDef.type];
|
||||
}
|
||||
}
|
||||
nextState.storedTypes = newFilters;
|
||||
// Lazy init the list for compatibility reasons
|
||||
if (!nextState.highlightSettings) {
|
||||
nextState.highlightSettings = [defaultHighlightSetting.id];
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user