From 16aeb51d7b848420d3e032fb16c3d650e060e681 Mon Sep 17 00:00:00 2001 From: QuiteLiterallyAnything <154708292+QuiteLiterallyAnything@users.noreply.github.com> Date: Sun, 2 Mar 2025 01:49:49 -0800 Subject: [PATCH] Adds a Fulpstation Changelog (#1345) * Commits a highly incomplete version of a Fulpstation changelog. * Further develops a basic, copied version of /tg/'s changelog. * Makes the changelog actually semi-functional. * Finalizes a few things... --- code/game/world.dm | 5 + code/modules/client/preferences.dm | 5 + .../changelogs/{archive => }/changelogs.md | 0 .../data/html/changelogs/fulp_changelog.dm | 88 +++++ fulp_modules/tg_edits.md | 10 +- interface/interface.dm | 2 +- tgstation.dme | 1 + .../packages/fulpui-patches/FulpChangelog.jsx | 371 ++++++++++++++++++ 8 files changed, 479 insertions(+), 3 deletions(-) rename fulp_modules/data/html/changelogs/{archive => }/changelogs.md (100%) create mode 100644 fulp_modules/data/html/changelogs/fulp_changelog.dm create mode 100644 tgui/packages/fulpui-patches/FulpChangelog.jsx diff --git a/code/game/world.dm b/code/game/world.dm index ea6c9cb976f..3ab058aef47 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -249,6 +249,11 @@ GLOBAL_PROTECT(tracy_init_reason) var/latest_changelog = file("[global.config.directory]/../html/changelogs/archive/" + time2text(world.timeofday, "YYYY-MM") + ".yml") GLOB.changelog_hash = fexists(latest_changelog) ? md5(latest_changelog) : 0 //for telling if the changelog has changed recently + // FULP EDIT // + var/latest_fulp_changelog = file("[global.config.directory]/../fulp_modules/data/html/changelogs/archive/" + time2text(world.timeofday, "YYYY-MM") + ".yml") + GLOB.fulp_changelog_hash = fexists(latest_fulp_changelog) ? md5(latest_fulp_changelog) : 0 + // FULP EDIT END // + if(GLOB.round_id) log_game("Round ID: [GLOB.round_id]") diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 545458537e1..33c81370911 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -21,6 +21,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) /// Cached changelog size, to detect new changelogs since last join var/lastchangelog = "" + /// FULP EDIT /// + /// Same as var above but for Fulpstation's changelog. + var/last_fulp_changelog = "" + /// FULP EDIT END /// + /// List of ROLE_X that the client wants to be eligible for var/list/be_special = list() //Special role selection diff --git a/fulp_modules/data/html/changelogs/archive/changelogs.md b/fulp_modules/data/html/changelogs/changelogs.md similarity index 100% rename from fulp_modules/data/html/changelogs/archive/changelogs.md rename to fulp_modules/data/html/changelogs/changelogs.md diff --git a/fulp_modules/data/html/changelogs/fulp_changelog.dm b/fulp_modules/data/html/changelogs/fulp_changelog.dm new file mode 100644 index 00000000000..a4420cd0822 --- /dev/null +++ b/fulp_modules/data/html/changelogs/fulp_changelog.dm @@ -0,0 +1,88 @@ +//-----------------------------------------// +// Fulpstation's Changelog // +//-----------------------------------------// + +/*** + * This file contains all DM code related to Fulpstation's changelog. + * + * Most of this is just a very rough copying of existing /tg/ code with "fulp" appended to it, + * so credit for all of it goes to the various people who made /tg/'s changelog. + **/ + + +/// FULP CHANGELOG DATUM /// + +GLOBAL_DATUM(fulp_changelog_tgui, /datum/fulp_changelog) +GLOBAL_VAR_INIT(fulp_changelog_hash, "") + +/datum/fulp_changelog + var/static/list/fulp_changelog_items = list() + +/datum/fulp_changelog/ui_state() + return GLOB.always_state + +/datum/fulp_changelog/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + ui = new(user, src, "FulpChangelog") + ui.open() + +/datum/fulp_changelog/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + if(action == "get_month") + var/datum/asset/fulp_changelog_item/fulp_changelog_item = fulp_changelog_items[params["date"]] + if (!fulp_changelog_item) + fulp_changelog_item = new /datum/asset/fulp_changelog_item(params["date"]) + fulp_changelog_items[params["date"]] = fulp_changelog_item + return ui.send_asset(fulp_changelog_item) + +/datum/fulp_changelog/ui_static_data() + var/list/data = list( "dates" = list() ) + var/regex/ymlRegex = regex(@"\.yml", "g") + + for(var/archive_file in sort_list(flist("fulp_modules/data/html/changelogs/archive/"))) + var/archive_date = ymlRegex.Replace(archive_file, "") + data["dates"] = list(archive_date) + data["dates"] + + return data + + +/// CHANGELOG VERB /// + +/client/verb/fulp_changelog() + set name = "Changelog" + set category = "OOC" + if(!GLOB.fulp_changelog_tgui) + GLOB.fulp_changelog_tgui = new /datum/fulp_changelog() + + GLOB.fulp_changelog_tgui.ui_interact(mob) + if(prefs.last_fulp_changelog != GLOB.fulp_changelog_hash) + prefs.last_fulp_changelog = GLOB.fulp_changelog_hash + prefs.save_preferences() + winset(src, "infowindow.changelog", "font-style=;") + + +/// FULP CHANGELOG ITEM ASSET /// + +/datum/asset/fulp_changelog_item + _abstract = /datum/asset/fulp_changelog_item + var/item_filename + +/datum/asset/fulp_changelog_item/New(date) + item_filename = SANITIZE_FILENAME("[date].yml") + SSassets.transport.register_asset(item_filename, file("fulp_modules/data/html/changelogs/archive/" + item_filename)) + +/datum/asset/fulp_changelog_item/send(client) + if (!item_filename) + return + . = SSassets.transport.send_assets(client, item_filename) + +/datum/asset/fulp_changelog_item/get_url_mappings() + if (!item_filename) + return + . = list("[item_filename]" = SSassets.transport.get_asset_url(item_filename)) + + +// See 'world.dm' for a changelog-related Fulp edit. // diff --git a/fulp_modules/tg_edits.md b/fulp_modules/tg_edits.md index 5c5200ca704..45d77a29a52 100644 --- a/fulp_modules/tg_edits.md +++ b/fulp_modules/tg_edits.md @@ -1,7 +1,5 @@ ## List of all TG edits: -- .github/workflows/compile_changelogs.yml > Same as above. - - code/datums/greyscale/_greyscale_config.dm > Adds our greyscales folder to the sanity check - code/game/area/areas/shuttles.dm > Plays ApproachingFulp instead of ApproachingTG @@ -18,6 +16,14 @@ - tools/pull_request_hooks/autoChangelog.js > Changes changelog folder to fulp_modules/data/html/changelogs, to preserve them across TGUs. +- .github\workflows\compile_changelogs.yml > Same as above. + +- code\game\world.dm > Marked by a "FULP EDIT" comment; copies a bit of code to make 'GLOB.fulp_changelog_hash' functional. + +- code\modules\client\preferences.dm > Marked by a "FULP EDIT" comment; gives clients the 'last_fulp_changelog' var. + +- interface\interface.dm > Changes the value of 'name' on '/client/verb/changelog' to "/TG/ Changelog" + ## All Fulp files not contained within /fulp_modules/ - code/__DEFINES/fulp_defines > Contains all of our defines diff --git a/interface/interface.dm b/interface/interface.dm index c90abd9583c..b13890677f4 100644 --- a/interface/interface.dm +++ b/interface/interface.dm @@ -99,7 +99,7 @@ /client/verb/changelog() - set name = "Changelog" + set name = "/TG/ Changelog" set category = "OOC" if(!GLOB.changelog_tgui) GLOB.changelog_tgui = new /datum/changelog() diff --git a/tgstation.dme b/tgstation.dme index a228c88de4d..6c43b0fb62a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6526,6 +6526,7 @@ #include "fulp_modules\_signals\bloodsuckers.dm" #include "fulp_modules\_signals\misc.dm" #include "fulp_modules\_signals\nanites.dm" +#include "fulp_modules\data\html\changelogs\fulp_changelog.dm" #include "fulp_modules\features\admin_chicanery\smites\catification.dm" #include "fulp_modules\features\antagonists\antag_tips\antag_tip_integration.dm" #include "fulp_modules\features\antagonists\antag_tips\preference.dm" diff --git a/tgui/packages/fulpui-patches/FulpChangelog.jsx b/tgui/packages/fulpui-patches/FulpChangelog.jsx new file mode 100644 index 00000000000..add55e14dc3 --- /dev/null +++ b/tgui/packages/fulpui-patches/FulpChangelog.jsx @@ -0,0 +1,371 @@ +import dateformat from 'dateformat'; +import yaml from 'js-yaml'; +import { Component, Fragment } from 'react'; +import { + Box, + Button, + Dropdown, + Icon, + Section, + Stack, + Table, +} from '../tgui/components'; +import { classes } from 'common/react'; + +import { resolveAsset } from '../tgui/assets'; +import { useBackend } from '../tgui/backend'; +import { Window } from '../tgui/layouts'; + +const icons = { + add: { icon: 'check-circle', color: 'green' }, + admin: { icon: 'user-shield', color: 'purple' }, + balance: { icon: 'balance-scale-right', color: 'yellow' }, + bugfix: { icon: 'bug', color: 'green' }, + code_imp: { icon: 'code', color: 'green' }, + config: { icon: 'cogs', color: 'purple' }, + expansion: { icon: 'check-circle', color: 'green' }, + experiment: { icon: 'radiation', color: 'yellow' }, + image: { icon: 'image', color: 'green' }, + imageadd: { icon: 'tg-image-plus', color: 'green' }, + imagedel: { icon: 'tg-image-minus', color: 'red' }, + qol: { icon: 'hand-holding-heart', color: 'green' }, + refactor: { icon: 'tools', color: 'green' }, + rscadd: { icon: 'check-circle', color: 'green' }, + rscdel: { icon: 'times-circle', color: 'red' }, + server: { icon: 'server', color: 'purple' }, + sound: { icon: 'volume-high', color: 'green' }, + soundadd: { icon: 'tg-sound-plus', color: 'green' }, + sounddel: { icon: 'tg-sound-minus', color: 'red' }, + spellcheck: { icon: 'spell-check', color: 'green' }, + map: { icon: 'map', color: 'green' }, + tgs: { icon: 'toolbox', color: 'purple' }, + tweak: { icon: 'wrench', color: 'green' }, + unknown: { icon: 'info-circle', color: 'label' }, + wip: { icon: 'hammer', color: 'orange' }, +}; + +export class FulpChangelog extends Component { + constructor(props) { + super(props); + this.state = { + data: 'Loading changelog data...', + selectedDate: '', + selectedIndex: 0, + }; + this.dateChoices = []; + } + + setData(data) { + this.setState({ data }); + } + + setSelectedDate(selectedDate) { + this.setState({ selectedDate }); + } + + setSelectedIndex(selectedIndex) { + this.setState({ selectedIndex }); + } + + getData = (date, attemptNumber = 1) => { + const { act } = useBackend(); + const self = this; + const maxAttempts = 6; + + if (attemptNumber > maxAttempts) { + return this.setData( + 'Failed to load data after ' + maxAttempts + ' attempts', + ); + } + + act('get_month', { date }); + + fetch(resolveAsset(date + '.yml')).then(async (changelogData) => { + const result = await changelogData.text(); + const errorRegex = /^Cannot find/; + + if (errorRegex.test(result)) { + const timeout = 50 + attemptNumber * 50; + + self.setData('Loading changelog data' + '.'.repeat(attemptNumber + 3)); + setTimeout(() => { + self.getData(date, attemptNumber + 1); + }, timeout); + } else { + self.setData(yaml.load(result, { schema: yaml.CORE_SCHEMA })); + } + }); + }; + + componentDidMount() { + const { + data: { dates = [] }, + } = useBackend(); + + if (dates) { + dates.forEach((date) => + this.dateChoices.push(dateformat(date, 'mmmm yyyy', true)), + ); + this.setSelectedDate(this.dateChoices[0]); + this.getData(dates[0]); + } + } + + render() { + const { data, selectedDate, selectedIndex } = this.state; + const { + data: { dates }, + } = useBackend(); + const { dateChoices } = this; + + const dateDropdown = dateChoices.length > 0 && ( + + +