Compare commits

..

No commits in common. "main" and "v2.4.0" have entirely different histories.
main ... v2.4.0

31 changed files with 2414 additions and 280 deletions

View file

@ -1,5 +1,2 @@
# The absolute path to the Foundry installation to create symlinks to # The absolute path to the Foundry installation to create symlinks to
FOUNDRY_ROOT="" FOUNDRY_ROOT=""
# The manifest file for the module/system
MANIFEST="./system.json"

View file

@ -1,17 +1,11 @@
on: [ workflow_dispatch ] on: [ workflow_dispatch ]
env:
MANIFEST: "system.json"
jobs: jobs:
create-draft-release: create-artifacts:
name: "Create Draft Release" name: "Create artifacts"
runs-on: act runs-on: act
outputs:
version: ${{steps.version.outputs.version}}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
submodules: true
- name: Install dependencies - name: Install dependencies
run: npm clean-install run: npm clean-install
@ -20,7 +14,7 @@ jobs:
run: cat system.json | echo version=`jq -r ".version"` >> "$FORGEJO_OUTPUT" run: cat system.json | echo version=`jq -r ".version"` >> "$FORGEJO_OUTPUT"
- name: Assert that the tag doesn't exist - name: Assert that the tag doesn't exist
run: node scripts/src/tagExists.mjs run: node scripts/tagExists.mjs
env: env:
TAG_NAME: "v${{steps.version.outputs.version}}" TAG_NAME: "v${{steps.version.outputs.version}}"
@ -30,53 +24,73 @@ jobs:
- name: Remove compendia source - name: Remove compendia source
run: "rm -rf packs/**/_source" run: "rm -rf packs/**/_source"
- name: Compress files
run: zip -r release.zip langs module styles templates README.md assets LICENSE
- name: Upload artifacts
uses: https://data.forgejo.org/forgejo/upload-artifact@v4
with:
path: |
system.json
release.zip
scripts/*.mjs
package-lock.json
package.json
retention-days: 7
if-no-files-found: error
forgejo-release:
name: "Create Forgejo release"
runs-on: act
needs:
- create-artifacts
if: vars.RELEASE_TO_FORGEJO == 'yes'
steps:
- name: Download artifacts
uses: https://data.forgejo.org/forgejo/download-artifact@v4
with:
merge-multiple: true
- name: Install dependencies
run: npm i
- id: version
run: cat system.json | echo version=`jq -r ".version"` >> "$FORGEJO_OUTPUT"
- name: Update manifest - name: Update manifest
run: node scripts/src/prepareManifest.mjs run: node scripts/prepareManifest.mjs
env: env:
DOWNLOAD_URL: "${{forgejo.server_url}}/${{forgejo.repository}}/releases/download/v${{steps.version.outputs.version}}/release.zip" DOWNLOAD_URL: "${{forgejo.server_url}}/${{forgejo.repository}}/releases/download/v${{steps.version.outputs.version}}/release.zip"
LATEST_URL: "${{forgejo.server_url}}/${{forgejo.repository}}/releases/download/latest/system.json" LATEST_URL: "${{forgejo.server_url}}/${{forgejo.repository}}/releases/download/latest/system.json"
- name: Compress files - name: Add manifest into release archive
run: zip -r release.zip langs module styles templates README.md assets LICENSE ${{env.MANIFEST}} run: zip release.zip --update system.json
- name: Create forgejo release - name: Upload archive to s3
run: node scripts/src/createForgejoRelease.mjs run: node scripts/uploadToS3.mjs
env:
TAG: "v${{steps.version.outputs.version}}"
FILE: "release.zip"
S3_BUCKET: "${{vars.S3_BUCKET}}"
S3_REGION: "${{vars.S3_REGION}}"
S3_KEY: "${{secrets.S3_KEY}}"
S3_SECRET: "${{secrets.S3_SECRET}}"
S3_ENDPOINT: "${{vars.S3_ENDPOINT}}"
- name: Upload manifest to s3
run: node scripts/uploadToS3.mjs
env:
TAG: "v${{steps.version.outputs.version}}"
FILE: "system.json"
S3_BUCKET: "${{vars.S3_BUCKET}}"
S3_REGION: "${{vars.S3_REGION}}"
S3_KEY: "${{secrets.S3_KEY}}"
S3_SECRET: "${{secrets.S3_SECRET}}"
S3_ENDPOINT: "${{vars.S3_ENDPOINT}}"
- name: Create draft release
run: node scripts/createForgejoRelease.mjs
env: env:
TAG: "v${{steps.version.outputs.version}}" TAG: "v${{steps.version.outputs.version}}"
CDN_URL: "${{vars.CDN_URL}}" CDN_URL: "${{vars.CDN_URL}}"
wiki-release-artifact:
name: "Add Wiki to Release"
runs-on: act
needs:
- create-draft-release
steps:
- name: Checkout main code
uses: actions/checkout@v4
with:
submodules: true
- name: "Clone wiki repo"
uses: actions/checkout@v4
with:
repository: "${{forgejo.repository}}.wiki"
ref: "main"
path: "wiki"
token: ${{forgejo.token}}
- name: "Install dependencies"
run: "pwd; npm i"
- name: "Remove development folders"
run: "rm -rf .git .vscode"
working-directory: "wiki"
- name: "Compress wiki folder"
run: "zip -r wiki.zip ."
working-directory: "wiki"
- name: "Upload wiki archive"
run: "node scripts/src/uploadReleaseAsset.mjs"
env:
ASSET: "wiki/wiki.zip"
TAG: "v${{needs.create-draft-release.outputs.version}}"

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "scripts"]
path = scripts
url = https://git.varify.ca/Foundry/scripts.git

View file

@ -10,10 +10,6 @@
"name": "Players Can Manage Attributes", "name": "Players Can Manage Attributes",
"hint": "This allows players who have edit access to a document to be able to edit what attributes those characters have via the attribute editor" "hint": "This allows players who have edit access to a document to be able to edit what attributes those characters have via the attribute editor"
}, },
"initiativeFormula": {
"name": "Initiative Formula",
"hint": "The dice formula used for initiative, this can reference attributes on the actor. If the actor doesn't have the attribute it will be interpreted as 0."
},
"sheetDefaultHeight": { "sheetDefaultHeight": {
"name": "Default Actor Sheet Height", "name": "Default Actor Sheet Height",
"hint": "The height that all actor sheets will open at unless overwridden for that sheet specifically. This setting will not affect already opened sheets." "hint": "The height that all actor sheets will open at unless overwridden for that sheet specifically. This setting will not affect already opened sheets."
@ -40,31 +36,9 @@
"Key": "Key", "Key": "Key",
"Value": "Value", "Value": "Value",
"no-data-submitted": "No data submitted", "no-data-submitted": "No data submitted",
"data-query-notif-header": "Data Query Notification", "data-query-notif-header": "Data Query Notification"
"cancel": "Cancel",
"confirm-and-close": "Confirm and Close",
"save-and-close": "Save and Close",
"delete": "Delete",
"resizable": "Resizable",
"not-resizable": "Not Resizable"
}, },
"Apps": { "Apps": {
"Ask": {
"title": "Questions",
"invalid-input-type": "Invalid input type provided: {type}"
},
"AttributeManager": {
"title": "Attributes: {name}",
"has-max": "Has Maximum?",
"name-placeholder": "Attribute Name...",
"no-attributes": "No attributes yet",
"add-new-attribute": "Add New Attribute"
},
"PlayerSheet": {
"manage-attributes": "Manage Attributes",
"current-value": "Current value",
"max-value": "Maximum value"
},
"QueryStatus": { "QueryStatus": {
"title": "Information Request Status", "title": "Information Request Status",
"user-disconnected-tooltip": "This user is not logged in to Foundry", "user-disconnected-tooltip": "This user is not logged in to Foundry",
@ -81,8 +55,7 @@
"label": "Height" "label": "Height"
}, },
"Resizable": { "Resizable": {
"label": "Resizable", "label": "Resizable"
"placeholder": "Default ({placeholder})"
}, },
"tabs": { "tabs": {
"foundry": "Foundry", "foundry": "Foundry",

View file

@ -1,5 +1,4 @@
import { __ID__, filePath } from "../consts.mjs"; import { __ID__, filePath } from "../consts.mjs";
import { localizer } from "../utils/localizer.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -25,7 +24,7 @@ export class Ask extends HandlebarsApplicationMixin(ApplicationV2) {
width: 330, width: 330,
}, },
window: { window: {
title: `taf.Apps.Ask.title`, title: `Questions`,
resizable: true, resizable: true,
minimizable: true, minimizable: true,
contentTag: `form`, contentTag: `form`,
@ -81,10 +80,7 @@ export class Ask extends HandlebarsApplicationMixin(ApplicationV2) {
for (const input of inputs) { for (const input of inputs) {
if (!validInputTypes.includes(input.type)) { if (!validInputTypes.includes(input.type)) {
input.details = localizer( input.details = `Invalid input type provided: ${input.type}`;
`taf.Apps.Ask.invalid-input-type`,
{ type: input.type },
);
input.type = `error`; input.type = `error`;
}; };
}; };

View file

@ -1,6 +1,5 @@
import { __ID__, filePath } from "../consts.mjs"; import { __ID__, filePath } from "../consts.mjs";
import { attributeSorter } from "../utils/attributeSort.mjs"; import { attributeSorter } from "../utils/attributeSort.mjs";
import { localizer } from "../utils/localizer.mjs";
import { toID } from "../utils/toID.mjs"; import { toID } from "../utils/toID.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -53,10 +52,7 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
}; };
get title() { get title() {
return localizer( return `Attributes: ${this.#doc.name}`;
`taf.Apps.AttributeManager.title`,
this.#doc,
);
}; };
// #endregion Instance Data // #endregion Instance Data
@ -106,6 +102,7 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
attrs.push({ attrs.push({
id, id,
name: data.name, name: data.name,
displayName: data.isNew ? `New Attribute` : data.name,
sort: data.sort, sort: data.sort,
isRange: data.isRange, isRange: data.isRange,
isNew: data.isNew ?? false, isNew: data.isNew ?? false,

View file

@ -82,7 +82,7 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
controls.push({ controls.push({
icon: `fa-solid fa-at`, icon: `fa-solid fa-at`,
label: `taf.Apps.PlayerSheet.manage-attributes`, label: `Manage Attributes`,
action: `manageAttributes`, action: `manageAttributes`,
visible: () => { visible: () => {
const isGM = game.user.isGM; const isGM = game.user.isGM;
@ -167,6 +167,7 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
event.stopPropagation(); event.stopPropagation();
if ( event.detail > 1 ) { return } if ( event.detail > 1 ) { return }
// const docSheetConfigWidth = TAFDocumentSheetConfig.DEFAULT_OPTIONS.position.width;
new TAFDocumentSheetConfig({ new TAFDocumentSheetConfig({
document: this.document, document: this.document,
position: { position: {

View file

@ -1,6 +1,5 @@
import { __ID__, filePath } from "../consts.mjs"; import { __ID__, filePath } from "../consts.mjs";
import { getDefaultSizing } from "../utils/getSizing.mjs"; import { getDefaultSizing } from "../utils/getSizing.mjs";
import { localizer } from "../utils/localizer.mjs";
const { diffObject, expandObject, flattenObject } = foundry.utils; const { diffObject, expandObject, flattenObject } = foundry.utils;
const { DocumentSheetConfig } = foundry.applications.apps; const { DocumentSheetConfig } = foundry.applications.apps;
@ -75,9 +74,7 @@ export class TAFDocumentSheetConfig extends DocumentSheetConfig {
const defaults = getDefaultSizing(); const defaults = getDefaultSizing();
context.placeholders = { context.placeholders = {
...defaults, ...defaults,
resizable: defaults.resizable resizable: defaults.resizable ? `Resizable` : `Not Resizable`,
? localizer(`taf.misc.resizable`)
: localizer(`taf.misc.not-resizable`),
}; };
// Custom values from document itself // Custom values from document itself
@ -91,15 +88,9 @@ export class TAFDocumentSheetConfig extends DocumentSheetConfig {
// Static prep // Static prep
context.resizeOptions = [ context.resizeOptions = [
{ { label: `Default (${context.placeholders.resizable})`, value: `` },
label: localizer( { label: `Resizable`, value: `true` },
`taf.Apps.TAFDocumentSheetConfig.Resizable.placeholder`, { label: `No Resizing`, value: `false` },
{ placeholder: context.placeholders.resizable },
),
value: ``,
},
{ label: localizer(`taf.misc.resizable`), value: `true` },
{ label: localizer(`taf.misc.not-resizable`), value: `false` },
]; ];
}; };
// #endregion Data Prep // #endregion Data Prep

View file

@ -1,9 +0,0 @@
import { __ID__ } from "../consts.mjs";
const { Combatant } = foundry.documents;
export class TAFCombatant extends Combatant {
_getInitiativeFormula() {
return game.settings.get(__ID__, `initiativeFormula`);
};
};

View file

@ -7,7 +7,6 @@ import { PlayerData } from "../data/Player.mjs";
// Documents // Documents
import { TAFActor } from "../documents/Actor.mjs"; import { TAFActor } from "../documents/Actor.mjs";
import { TAFCombatant } from "../documents/Combatant.mjs";
import { TAFItem } from "../documents/Item.mjs"; import { TAFItem } from "../documents/Item.mjs";
import { TAFTokenDocument } from "../documents/Token.mjs"; import { TAFTokenDocument } from "../documents/Token.mjs";
@ -26,7 +25,6 @@ Hooks.on(`init`, () => {
CONFIG.Token.documentClass = TAFTokenDocument; CONFIG.Token.documentClass = TAFTokenDocument;
CONFIG.Actor.documentClass = TAFActor; CONFIG.Actor.documentClass = TAFActor;
CONFIG.Combatant.documentClass = TAFCombatant;
CONFIG.Actor.dataModels.player = PlayerData; CONFIG.Actor.dataModels.player = PlayerData;

View file

@ -3,16 +3,6 @@ import { __ID__ } from "../consts.mjs";
const { NumberField, StringField } = foundry.data.fields; const { NumberField, StringField } = foundry.data.fields;
export function registerWorldSettings() { export function registerWorldSettings() {
game.settings.register(__ID__, `initiativeFormula`, {
name: `taf.settings.initiativeFormula.name`,
hint: `taf.settings.initiativeFormula.hint`,
config: true,
type: String,
default: `1d20`,
scope: `world`,
});
game.settings.register(__ID__, `canPlayersManageAttributes`, { game.settings.register(__ID__, `canPlayersManageAttributes`, {
name: `taf.settings.canPlayersManageAttributes.name`, name: `taf.settings.canPlayersManageAttributes.name`,
hint: `taf.settings.canPlayersManageAttributes.hint`, hint: `taf.settings.canPlayersManageAttributes.hint`,

View file

@ -1,4 +1,4 @@
import { close } from "../../utils/DialogManager.mjs"; import { DialogManager } from "../../utils/DialogManager.mjs";
import { localizer } from "../../utils/localizer.mjs"; import { localizer } from "../../utils/localizer.mjs";
export async function queryCancel(payload) { export async function queryCancel(payload) {
@ -15,5 +15,5 @@ export async function queryCancel(payload) {
return; return;
}; };
close(id); await DialogManager.close(id);
}; };

View file

@ -1,4 +1,4 @@
import { ask } from "../../utils/DialogManager.mjs"; import { DialogManager } from "../../utils/DialogManager.mjs";
import { localizer } from "../../utils/localizer.mjs"; import { localizer } from "../../utils/localizer.mjs";
import { respondedToQueries } from "../../utils/QueryManager.mjs"; import { respondedToQueries } from "../../utils/QueryManager.mjs";
@ -36,7 +36,7 @@ export async function queryPrompt(payload) {
if (users != null && !users.includes(game.user.id)) { return }; if (users != null && !users.includes(game.user.id)) { return };
request.id = id; request.id = id;
const result = await ask(request, config); const result = await DialogManager.ask(request, config);
if (result.state === `fronted`) { if (result.state === `fronted`) {
return; return;
} else if (result.state === `errored`) { } else if (result.state === `errored`) {

2123
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,16 +1,18 @@
{ {
"devDependencies": { "devDependencies": {
"@aws-sdk/client-s3": "^3.934.0",
"@eslint/js": "^9.8.0", "@eslint/js": "^9.8.0",
"@foundryvtt/foundryvtt-cli": "^1.0.3", "@foundryvtt/foundryvtt-cli": "^1.0.3",
"@stylistic/eslint-plugin": "^2.6.1", "@stylistic/eslint-plugin": "^2.6.1",
"axios": "^1.13.2",
"dotenv": "^17.2.2",
"eslint": "^9.8.0", "eslint": "^9.8.0",
"globals": "^15.9.0", "globals": "^15.9.0"
"scripts": "file:./scripts"
}, },
"scripts": { "scripts": {
"data:build": "node scripts/src/buildCompendia.mjs", "data:build": "node scripts/buildCompendia.mjs",
"data:extract": "node scripts/src/extractCompendia.mjs", "data:extract": "node scripts/extractCompendia.mjs",
"link": "node scripts/src/linkFoundry.mjs", "link": "node scripts/linkFoundry.mjs",
"lint": "eslint --fix", "lint": "eslint --fix",
"lint:nofix": "eslint" "lint:nofix": "eslint"
} }

@ -1 +0,0 @@
Subproject commit 06fb33b35ff446dee613afe271b6fe2ff976735a

View file

@ -0,0 +1,32 @@
import { compilePack } from "@foundryvtt/foundryvtt-cli";
import { existsSync } from "fs";
import { join } from "path";
import { readFile } from "fs/promises";
async function main() {
const system = JSON.parse(await readFile(`./system.json`, `utf-8`));
if (!system.packs || system.packs.length === 0) {
console.log(`No compendium packs defined`);
process.exit(0);
};
for (const compendium of system.packs) {
console.debug(`Packing ${compendium.label} (${compendium.name})`);
let src = join(process.cwd(), compendium.path, `_source`);
if (!existsSync(src)) {
console.warn(`${compendium.path} doesn't exist, skipping.`)
continue;
};
await compilePack(
src,
join(process.cwd(), compendium.path),
{ recursive: true },
);
console.debug(`Finished packing ${compendium.name}`);
};
console.log(`Finished packing compendia`)
};
main();

View file

@ -0,0 +1,55 @@
import axios from "axios";
const {
TAG,
FORGEJO_SERVER_URL: WEB_URL,
FORGEJO_API_URL: API,
FORGEJO_REPOSITORY: REPO,
FORGEJO_TOKEN: TOKEN,
CDN_URL,
} = process.env;
async function addReleaseAsset(releaseID, name) {
return axios.post(
`${API}/repos/${REPO}/releases/${releaseID}/assets`,
{ external_url: `${CDN_URL}/${REPO}/${TAG}/${name}`, },
{
headers: {
Authorization: `token ${TOKEN}`,
"Content-Type": `multipart/form-data`,
},
params: { name },
}
);
};
async function main() {
// Initial Release Data
const release = await axios.post(
`${API}/repos/${REPO}/releases`,
{
name: TAG,
tag_name: TAG,
draft: true,
hide_archive_links: true,
target_commitish: `main`,
body: `<!-- Manifest URL: ${WEB_URL}/${REPO}/releases/download/${TAG}/system.json -->`,
},
{
headers: { Authorization: `token ${TOKEN}` },
}
);
try {
await addReleaseAsset(release.data.id, `release.zip`);
await addReleaseAsset(release.data.id, `system.json`);
} catch (e) {
console.error(`Failed to add assets to the release`);
process.exit(1);
};
console.log(`Release created`);
};
main();

View file

@ -0,0 +1,27 @@
import { readFile } from "fs/promises";
import { join } from "path";
import { extractPack } from "@foundryvtt/foundryvtt-cli";
async function main() {
const system = JSON.parse(await readFile(`./system.json`, `utf-8`));
if (!system.packs || system.packs.length === 0) {
console.log(`No compendium packs defined`);
process.exit(0);
};
for (const compendium of system.packs) {
console.debug(`Unpacking ${compendium.label} (${compendium.name})`);
let src = join(process.cwd(), compendium.path, `_source`);
await extractPack(
join(process.cwd(), compendium.path),
src,
{ recursive: true },
);
console.debug(`Finished packing ${compendium.name}`);
};
console.log(`Finished unpacking compendia`);
};
main();

47
scripts/linkFoundry.mjs Normal file
View file

@ -0,0 +1,47 @@
import { existsSync } from "fs";
import { symlink, unlink } from "fs/promises";
import { join } from "path";
import { config } from "dotenv";
config({ quiet: true });
const root = process.env.FOUNDRY_ROOT;
// Early exit
if (!root) {
console.error(`Must provide a FOUNDRY_ROOT environment variable`);
process.exit(1);
};
// Assert Foundry exists
if (!existsSync(root)) {
console.error(`Foundry root not found.`);
process.exit(1);
};
// Removing existing symlink
if (existsSync(`foundry`)) {
console.log(`Attempting to unlink foundry instance`);
try {
await unlink(`foundry`);
} catch {
console.error(`Failed to unlink foundry folder.`);
process.exit(1);
};
};
// Account for if the root is pointing at an Electron install
let targetRoot = root;
if (existsSync(join(root, `resources`, `app`))) {
console.log(`Switching to use the "${root}/resources/app" directory`);
targetRoot = join(root, `resources`, `app`);
};
// Create symlink
console.log(`Linking foundry source into folder`)
try {
await symlink(targetRoot, `foundry`);
} catch (e) {
console.error(e);
process.exit(1);
};

View file

@ -0,0 +1,4 @@
const invalids = game.actors.invalidDocumentIds;
invalids.forEach(id => {
game.actors.getInvalid(id).delete();
});

View file

@ -0,0 +1,4 @@
const invalids = game.items.invalidDocumentIds;
invalids.forEach(id => {
game.items.getInvalid(id).delete();
});

View file

@ -0,0 +1,45 @@
/*
The intent of this script is to do all of the modifications of the
manifest file that we need to do in order to release the system.
This can include removing dev-only fields/attributes that end
users will never, and should never, care about nor need.
*/
import { readFile, writeFile } from "fs/promises";
const MANIFEST_PATH = `system.json`;
const {
DOWNLOAD_URL,
LATEST_URL,
} = process.env;
let manifest;
try {
manifest = JSON.parse(await readFile(MANIFEST_PATH, `utf-8`));
console.log(`Manifest loaded from disk`);
} catch {
console.error(`Failed to parse manifest file.`);
process.exit(1);
};
console.log(`Updating download/manifest URLs`)
manifest.download = DOWNLOAD_URL;
manifest.manifest = LATEST_URL;
// Filter out dev-only resources
if (manifest.esmodules) {
console.log(`Removing dev-only esmodules`);
manifest.esmodules = manifest.esmodules.filter(
filepath => !filepath.startsWith(`dev/`)
);
};
// Remove dev flags
console.log(`Cleaning up flags`);
delete manifest.flags?.hotReload;
if (Object.keys(manifest.flags).length === 0) {
delete manifest.flags;
};
await writeFile(MANIFEST_PATH, JSON.stringify(manifest, undefined, `\t`));
console.log(`Manifest written back to disk`);

38
scripts/tagExists.mjs Normal file
View file

@ -0,0 +1,38 @@
import axios from "axios";
const {
TAG_NAME,
FORGEJO_API_URL: API_URL,
FORGEJO_REPOSITORY: REPO,
FORGEJO_TOKEN: TOKEN,
} = process.env;
async function main() {
if (!TAG_NAME) {
console.log(`Tag name must not be blank`);
process.exit(1);
};
const requestURL = `${API_URL}/repos/${REPO}/tags/${TAG_NAME}`;
const response = await axios.get(
requestURL,
{
headers: { Authorization: `token ${TOKEN}` },
validateStatus: () => true,
},
);
// We actually *want* an error when the tag exists, instead of when
// it doesn't
if (response.status === 200) {
console.log(`Tag with name "${TAG_NAME}" already exists`);
process.exit(1);
};
console.log(`Tag with name "${TAG_NAME}" not found, proceeding`);
};
main();

65
scripts/uploadToS3.mjs Normal file
View file

@ -0,0 +1,65 @@
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { createReadStream } from "fs";
const requiredEnvVariables = [
`TAG`, `FILE`,
`FORGEJO_REPOSITORY`,
`S3_BUCKET`, `S3_REGION`, `S3_KEY`, `S3_SECRET`, `S3_ENDPOINT`,
];
async function main() {
// Assert all of the required env variables are present
const missing = [];
for (const envVar of requiredEnvVariables) {
if (!(envVar in process.env)) {
missing.push(envVar);
};
};
if (missing.length > 0) {
console.error(`Missing the following required environment variables: ${missing.join(`, `)}`);
process.exit(1);
};
const {
TAG,
S3_ENDPOINT,
S3_REGION,
S3_KEY,
S3_SECRET,
S3_BUCKET,
FILE,
FORGEJO_REPOSITORY: REPO,
} = process.env;
const s3Client = new S3Client({
endpoint: S3_ENDPOINT,
forcePathStyle: false,
region: S3_REGION,
credentials: {
accessKeyId: S3_KEY,
secretAccessKey: S3_SECRET
},
});
const name = FILE.split(`/`).at(-1);
const params = {
Bucket: S3_BUCKET,
Key: `${REPO}/${TAG}/${name}`,
Body: createReadStream(FILE),
ACL: "public-read",
METADATA: {
"x-repo-version": TAG,
},
};
try {
const response = await s3Client.send(new PutObjectCommand(params));
console.log("Upload successful");
} catch (err) {
console.error("Upload to s3 failed");
};
};
main();

View file

@ -2,7 +2,7 @@
"id": "taf", "id": "taf",
"title": "Text-Based Actors", "title": "Text-Based Actors",
"description": "An intentionally minimalist system that enables you to play rules-light games without getting in your way!", "description": "An intentionally minimalist system that enables you to play rules-light games without getting in your way!",
"version": "2.5.0", "version": "2.4.0",
"download": "", "download": "",
"manifest": "", "manifest": "",
"url": "https://git.varify.ca/Foundry/taf", "url": "https://git.varify.ca/Foundry/taf",

View file

@ -3,11 +3,11 @@
type="button" type="button"
data-action="cancel" data-action="cancel"
> >
{{localize "taf.misc.cancel"}} Cancel
</button> </button>
<button <button
type="submit" type="submit"
> >
{{localize "taf.misc.confirm-and-close"}} Confirm and Close
</button> </button>
</div> </div>

View file

@ -15,13 +15,13 @@
type="text" type="text"
data-bind="{{ attr.id }}.name" data-bind="{{ attr.id }}.name"
value="{{ attr.name }}" value="{{ attr.name }}"
placeholder="{{localize "taf.Apps.AttributeManager.name-placeholder"}}" placeholder="Attribute Name..."
> >
{{else}} {{else}}
<span>{{ attr.name }}</span> <span>{{ attr.name }}</span>
{{/if}} {{/if}}
<label> <label>
{{localize "taf.Apps.AttributeManager.has-max"}} Has Maximum?
<input <input
type="checkbox" type="checkbox"
data-bind="{{ attr.id }}.isRange" data-bind="{{ attr.id }}.isRange"
@ -32,12 +32,10 @@
type="button" type="button"
data-action="removeAttribute" data-action="removeAttribute"
> >
{{localize "taf.misc.delete"}} Delete
</button> </button>
</div> </div>
{{else}} {{else}}
<p> <p>No attributes yet</p>
{{localize "taf.Apps.AttributeManager.no-attributes"}}
</p>
{{/each}} {{/each}}
</div> </div>

View file

@ -3,11 +3,11 @@
type="button" type="button"
data-action="addNew" data-action="addNew"
> >
{{localize "taf.Apps.AttributeManager.add-new-attribute"}} Add New Attribute
</button> </button>
<button <button
type="submit" type="submit"
> >
{{localize "taf.misc.save-and-close"}} Save and Close
</button> </button>
</div> </div>

View file

@ -11,7 +11,7 @@
class="attr-range__value" class="attr-range__value"
name="{{attr.path}}.value" name="{{attr.path}}.value"
value="{{attr.value}}" value="{{attr.value}}"
aria-label="{{localize "taf.Apps.PlayerSheet.current-value"}}" aria-label="Current value"
data-tooltip="@{{ attr.id }}{{#if attr.isRange}}.value{{/if}}" data-tooltip="@{{ attr.id }}{{#if attr.isRange}}.value{{/if}}"
> >
{{#if attr.isRange}} {{#if attr.isRange}}
@ -21,7 +21,7 @@
class="attr-range__max" class="attr-range__max"
name="{{attr.path}}.max" name="{{attr.path}}.max"
value="{{attr.max}}" value="{{attr.max}}"
aria-label="{{localize "taf.Apps.PlayerSheet.max-value"}}" aria-label="Maximum value"
data-tooltip="@{{ attr.id }}.max" data-tooltip="@{{ attr.id }}.max"
> >
{{/if}} {{/if}}

View file

@ -12,6 +12,6 @@
name="name" name="name"
class="large" class="large"
value="{{actor.name}}" value="{{actor.name}}"
placeholder="{{ localize "Name" }}" placeholder="{{ localize 'Name' }}"
/> />
</header> </header>