mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-03-10 05:35:05 +08:00
Added Ape Keys Popup (#2642)
* added disabled field to simple popup input * inverted disabled logic * fixed initial value completely not working in simple popups * loading ape keys into the snapshot * added type for ape keys * only vertical resize for textareas * added before init function added can close parameter correclty handling textearas * storing active popup in a variable * fixed click handler * hiding text element if string is empty * updated ape keys types * added click handler to open ape keys popup * added simple poopups for generating, editing and deleting ape keys * added ape keys popup * updated ape key type * ape keys is optional * not getting ape keys by default * added function to get ape keys * refactor * using last used on property
This commit is contained in:
parent
134389515c
commit
f221326f47
10 changed files with 557 additions and 20 deletions
|
@ -14,10 +14,9 @@ export default function getApeKeysEndpoints(
|
|||
|
||||
async function update(
|
||||
apeKeyId: string,
|
||||
name: string,
|
||||
enabled: boolean
|
||||
updates: { name?: string; enabled?: boolean }
|
||||
): Ape.EndpointData {
|
||||
const payload = { name, enabled };
|
||||
const payload = { ...updates };
|
||||
return await apeClient.patch(`${BASE_PATH}/${apeKeyId}`, { payload });
|
||||
}
|
||||
|
||||
|
|
3
frontend/src/scripts/ape/types/ape.d.ts
vendored
3
frontend/src/scripts/ape/types/ape.d.ts
vendored
|
@ -136,8 +136,7 @@ declare namespace Ape {
|
|||
generate: (name: string, enabled: boolean) => EndpointData;
|
||||
update: (
|
||||
apeKeyId: string,
|
||||
name: string,
|
||||
enabled: boolean
|
||||
updates: { name?: string; enabled?: boolean }
|
||||
) => EndpointData;
|
||||
delete: (apeKeyId: string) => EndpointData;
|
||||
};
|
||||
|
|
|
@ -182,6 +182,28 @@ export async function getUserResults(): Promise<boolean> {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getUserApeKeys(): Promise<
|
||||
MonkeyTypes.ApeKeys | undefined
|
||||
> {
|
||||
const user = firebase.auth().currentUser;
|
||||
if (user == null) return undefined;
|
||||
if (dbSnapshot === null) return undefined;
|
||||
if (dbSnapshot.apeKeys !== undefined) {
|
||||
return dbSnapshot.apeKeys;
|
||||
} else {
|
||||
const response = await Ape.apeKeys.get();
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add("Error getting ape keys: " + response.message, -1);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
dbSnapshot.apeKeys = response.data as MonkeyTypes.ApeKeys;
|
||||
return dbSnapshot.apeKeys;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getUserHighestWpm<M extends MonkeyTypes.Mode>(
|
||||
mode: M,
|
||||
mode2: MonkeyTypes.Mode2<M>,
|
||||
|
|
|
@ -12,6 +12,7 @@ import * as ImportExportSettingsPopup from "../popups/import-export-settings-pop
|
|||
import * as CustomThemePopup from "../popups/custom-theme-popup";
|
||||
import * as ConfigEvent from "../observables/config-event";
|
||||
import * as ActivePage from "../states/active-page";
|
||||
import * as ApeKeysPopup from "../popups/ape-keys-popup";
|
||||
import Page from "./page";
|
||||
|
||||
type SettingsGroups = {
|
||||
|
@ -948,10 +949,14 @@ $("#shareCustomThemeButton").click(() => {
|
|||
);
|
||||
});
|
||||
|
||||
$(".pageSettings .sectionGroupTitle").click((e) => {
|
||||
$(".pageSettings .sectionGroupTitle").on("click", (e) => {
|
||||
toggleSettingsGroup($(e.currentTarget).attr("group") as string);
|
||||
});
|
||||
|
||||
$(".pageSettings .section.apeKeys #showApeKeysPopup").on("click", () => {
|
||||
ApeKeysPopup.show();
|
||||
});
|
||||
|
||||
$(".pageSettings .section.customBackgroundSize .inputAndButton .save").on(
|
||||
"click",
|
||||
() => {
|
||||
|
@ -982,7 +987,7 @@ $(".pageSettings .section.customLayoutfluid .inputAndButton .save").on(
|
|||
$(
|
||||
".pageSettings .section.customLayoutfluid .inputAndButton input"
|
||||
).val() as MonkeyTypes.CustomLayoutFluidSpaces
|
||||
).then(bool => {
|
||||
).then((bool) => {
|
||||
if (bool) {
|
||||
Notifications.add("Custom layoutfluid saved", 1);
|
||||
}
|
||||
|
@ -997,8 +1002,8 @@ $(".pageSettings .section.customLayoutfluid .inputAndButton .input").keypress(
|
|||
$(
|
||||
".pageSettings .section.customLayoutfluid .inputAndButton input"
|
||||
).val() as MonkeyTypes.CustomLayoutFluidSpaces
|
||||
).then(bool => {
|
||||
if (bool) {
|
||||
).then((bool) => {
|
||||
if (bool) {
|
||||
Notifications.add("Custom layoutfluid saved", 1);
|
||||
}
|
||||
});
|
||||
|
|
127
frontend/src/scripts/popups/ape-keys-popup.ts
Normal file
127
frontend/src/scripts/popups/ape-keys-popup.ts
Normal file
|
@ -0,0 +1,127 @@
|
|||
import * as DB from "../db";
|
||||
import Ape from "../ape";
|
||||
import * as Loader from "../elements/loader";
|
||||
import * as Notifications from "../elements/notifications";
|
||||
|
||||
function refreshList(): void {
|
||||
const data = DB.getSnapshot().apeKeys;
|
||||
if (!data) return;
|
||||
const table = $("#apeKeysPopupWrapper table tbody");
|
||||
table.empty();
|
||||
const apeKeyIds = Object.keys(data);
|
||||
if (apeKeyIds.length === 0) {
|
||||
table.append(
|
||||
"<tr><td colspan='6' style='text-align: center;'>No keys found</td></tr>"
|
||||
);
|
||||
return;
|
||||
}
|
||||
apeKeyIds.forEach((apeKeyId) => {
|
||||
const key = data[apeKeyId] as MonkeyTypes.ApeKey;
|
||||
table.append(`
|
||||
<tr keyId="${apeKeyId}">
|
||||
<td>
|
||||
<div class="icon-button">
|
||||
${
|
||||
key.enabled
|
||||
? `<i class="fas fa-check-square"></i>`
|
||||
: `<i class="far fa-fw fa-square"></i>`
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
<td>${key.name}</td>
|
||||
<td>${moment(key.createdOn).format("DD MMM YYYY HH:mm")}</td>
|
||||
<td>${moment(key.modifiedOn).format("DD MMM YYYY HH:mm")}</td>
|
||||
<td>${
|
||||
key.lastUsedOn === -1
|
||||
? "-"
|
||||
: moment(key.lastUsedOn).format("DD MMM YYYY HH:mm")
|
||||
}</td>
|
||||
<td>
|
||||
<div class="keyButtons">
|
||||
<div class="button edit">
|
||||
<i class="fas fa-fw fa-pen"></i>
|
||||
</div>
|
||||
<div class="button delete">
|
||||
<i class="fas fa-fw fa-trash-alt"></i>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
}
|
||||
|
||||
export function hide(): void {
|
||||
if (!$("#apeKeysPopupWrapper").hasClass("hidden")) {
|
||||
$("#apeKeysPopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
100,
|
||||
() => {
|
||||
$("#apeKeysPopupWrapper").addClass("hidden");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//show the popup
|
||||
export async function show(): Promise<void> {
|
||||
if ($("#apeKeysPopupWrapper").hasClass("hidden")) {
|
||||
Loader.show();
|
||||
await DB.getUserApeKeys();
|
||||
Loader.hide();
|
||||
refreshList();
|
||||
$("#apeKeysPopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 0)
|
||||
.removeClass("hidden")
|
||||
.animate(
|
||||
{
|
||||
opacity: 1,
|
||||
},
|
||||
100,
|
||||
() => {
|
||||
$("#apeKeysPopup textarea").focus().select();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$("#apeKeysPopupWrapper").on("mousedown", (e) => {
|
||||
if ($(e.target).attr("id") === "apeKeysPopupWrapper") {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#apeKeysPopup .generateApeKey").on("click", () => {
|
||||
hide();
|
||||
});
|
||||
|
||||
$(document).on("click", "#apeKeysPopup table .keyButtons .button", () => {
|
||||
hide();
|
||||
});
|
||||
|
||||
$(document).on("click", "#apeKeysPopup table .icon-button", async (e) => {
|
||||
const keyId = $(e.target).closest("tr").attr("keyId") as string;
|
||||
const snap = DB.getSnapshot();
|
||||
const key = snap.apeKeys?.[keyId];
|
||||
if (!key || !snap.apeKeys) return;
|
||||
Loader.show();
|
||||
const response = await Ape.apeKeys.update(keyId, { enabled: !key.enabled });
|
||||
Loader.hide();
|
||||
if (response.status !== 200) {
|
||||
return Notifications.add("Failed to update key: " + response.message, -1);
|
||||
}
|
||||
snap.apeKeys[keyId].enabled = !key.enabled;
|
||||
DB.setSnapshot(snap);
|
||||
refreshList();
|
||||
if (key.enabled) {
|
||||
Notifications.add("Key active", 1);
|
||||
} else {
|
||||
Notifications.add("Key inactive", 1);
|
||||
}
|
||||
});
|
|
@ -6,14 +6,18 @@ import * as UpdateConfig from "../config";
|
|||
import * as Loader from "../elements/loader";
|
||||
import * as Notifications from "../elements/notifications";
|
||||
import * as Settings from "../pages/settings";
|
||||
import * as ApeKeysPopup from "../popups/ape-keys-popup";
|
||||
|
||||
type Input = {
|
||||
placeholder: string;
|
||||
type?: string;
|
||||
initVal: string;
|
||||
hidden?: boolean;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
let activePopup: SimplePopup | null = null;
|
||||
|
||||
export const list: { [key: string]: SimplePopup } = {};
|
||||
class SimplePopup {
|
||||
parameters: string[];
|
||||
|
@ -26,7 +30,9 @@ class SimplePopup {
|
|||
text: string;
|
||||
buttonText: string;
|
||||
execFn: (thisPopup: SimplePopup, ...params: string[]) => void | Promise<void>;
|
||||
beforeInitFn: (thisPopup: SimplePopup) => void;
|
||||
beforeShowFn: (thisPopup: SimplePopup) => void;
|
||||
canClose: boolean;
|
||||
constructor(
|
||||
id: string,
|
||||
type: string,
|
||||
|
@ -38,6 +44,7 @@ class SimplePopup {
|
|||
thisPopup: SimplePopup,
|
||||
...params: string[]
|
||||
) => void | Promise<void>,
|
||||
beforeInitFn: (thisPopup: SimplePopup) => void,
|
||||
beforeShowFn: (thisPopup: SimplePopup) => void
|
||||
) {
|
||||
this.parameters = [];
|
||||
|
@ -51,7 +58,9 @@ class SimplePopup {
|
|||
this.wrapper = $("#simplePopupWrapper");
|
||||
this.element = $("#simplePopup");
|
||||
this.buttonText = buttonText;
|
||||
this.beforeInitFn = (thisPopup): void => beforeInitFn(thisPopup);
|
||||
this.beforeShowFn = (thisPopup): void => beforeShowFn(thisPopup);
|
||||
this.canClose = true;
|
||||
}
|
||||
reset(): void {
|
||||
this.element.html(`
|
||||
|
@ -78,6 +87,12 @@ class SimplePopup {
|
|||
el.find(".button").text(this.buttonText);
|
||||
}
|
||||
|
||||
if (this.text === "") {
|
||||
el.find(".text").addClass("hidden");
|
||||
} else {
|
||||
el.find(".text").removeClass("hidden");
|
||||
}
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
|
@ -90,7 +105,7 @@ class SimplePopup {
|
|||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
val="${input.initVal}"
|
||||
value="${input.initVal}"
|
||||
placeholder="${input.placeholder}"
|
||||
class="${input.hidden ? "hidden" : ""}"
|
||||
${input.hidden ? "" : "required"}
|
||||
|
@ -101,24 +116,38 @@ class SimplePopup {
|
|||
} else if (this.type === "text") {
|
||||
this.inputs.forEach((input) => {
|
||||
if (input.type) {
|
||||
el.find(".inputs").append(`
|
||||
if (input.type === "textarea") {
|
||||
el.find(".inputs").append(`
|
||||
<textarea
|
||||
placeholder="${input.placeholder}"
|
||||
class="${input.hidden ? "hidden" : ""}"
|
||||
${input.hidden ? "" : "required"}
|
||||
${input.disabled ? "disabled" : ""}
|
||||
autocomplete="off"
|
||||
>${input.initVal}</textarea>
|
||||
`);
|
||||
} else {
|
||||
el.find(".inputs").append(`
|
||||
<input
|
||||
type="${input.type}"
|
||||
val="${input.initVal}"
|
||||
placeholder="${input.placeholder}"
|
||||
class="${input.hidden ? "hidden" : ""}"
|
||||
${input.hidden ? "" : "required"}
|
||||
autocomplete="off"
|
||||
type="${input.type}"
|
||||
value="${input.initVal}"
|
||||
placeholder="${input.placeholder}"
|
||||
class="${input.hidden ? "hidden" : ""}"
|
||||
${input.hidden ? "" : "required"}
|
||||
${input.disabled ? "disabled" : ""}
|
||||
autocomplete="off"
|
||||
>
|
||||
`);
|
||||
`);
|
||||
}
|
||||
} else {
|
||||
el.find(".inputs").append(`
|
||||
<input
|
||||
type="text"
|
||||
val="${input.initVal}"
|
||||
value="${input.initVal}"
|
||||
placeholder="${input.placeholder}"
|
||||
class="${input.hidden ? "hidden" : ""}"
|
||||
${input.hidden ? "" : "required"}
|
||||
${input.disabled ? "disabled" : ""}
|
||||
autocomplete="off"
|
||||
>
|
||||
`);
|
||||
|
@ -132,6 +161,7 @@ class SimplePopup {
|
|||
}
|
||||
|
||||
exec(): void {
|
||||
if (!this.canClose) return;
|
||||
const vals: string[] = [];
|
||||
$.each($("#simplePopup input"), (_, el) => {
|
||||
vals.push($(el).val() as string);
|
||||
|
@ -141,9 +171,11 @@ class SimplePopup {
|
|||
}
|
||||
|
||||
show(parameters: string[] = []): void {
|
||||
activePopup = this;
|
||||
this.parameters = parameters;
|
||||
this.beforeShowFn(this);
|
||||
this.beforeInitFn(this);
|
||||
this.init();
|
||||
this.beforeShowFn(this);
|
||||
this.wrapper
|
||||
.stop(true, true)
|
||||
.css("opacity", 0)
|
||||
|
@ -154,6 +186,8 @@ class SimplePopup {
|
|||
}
|
||||
|
||||
hide(): void {
|
||||
if (!this.canClose) return;
|
||||
activePopup = null;
|
||||
this.wrapper
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
|
@ -165,6 +199,7 @@ class SimplePopup {
|
|||
}
|
||||
|
||||
export function hide(): void {
|
||||
if (activePopup) return activePopup.hide();
|
||||
$("#simplePopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
|
@ -176,6 +211,7 @@ export function hide(): void {
|
|||
|
||||
$("#simplePopupWrapper").mousedown((e) => {
|
||||
if ($(e.target).attr("id") === "simplePopupWrapper") {
|
||||
if (activePopup) return activePopup.hide();
|
||||
$("#simplePopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
|
@ -266,6 +302,9 @@ list["updateEmail"] = new SimplePopup(
|
|||
thisPopup.buttonText = "";
|
||||
thisPopup.text = "Password authentication is not enabled";
|
||||
}
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -338,6 +377,9 @@ list["updateName"] = new SimplePopup(
|
|||
thisPopup.inputs[0].hidden = true;
|
||||
thisPopup.buttonText = "Reauthenticate to update";
|
||||
}
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -400,6 +442,9 @@ list["updatePassword"] = new SimplePopup(
|
|||
thisPopup.buttonText = "";
|
||||
thisPopup.text = "Password authentication is not enabled";
|
||||
}
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -449,6 +494,9 @@ list["addPasswordAuth"] = new SimplePopup(
|
|||
},
|
||||
() => {
|
||||
//
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -526,6 +574,9 @@ list["deleteAccount"] = new SimplePopup(
|
|||
thisPopup.inputs = [];
|
||||
thisPopup.buttonText = "Reauthenticate to delete";
|
||||
}
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -569,6 +620,9 @@ list["clearTagPb"] = new SimplePopup(
|
|||
},
|
||||
(thisPopup) => {
|
||||
thisPopup.text = `Are you sure you want to clear PB for tag ${thisPopup.parameters[1]}?`;
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -585,6 +639,9 @@ list["applyCustomFont"] = new SimplePopup(
|
|||
},
|
||||
() => {
|
||||
//
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -643,6 +700,9 @@ list["resetPersonalBests"] = new SimplePopup(
|
|||
thisPopup.inputs = [];
|
||||
thisPopup.buttonText = "Reauthenticate to reset";
|
||||
}
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -661,6 +721,9 @@ list["resetSettings"] = new SimplePopup(
|
|||
},
|
||||
() => {
|
||||
//
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -689,6 +752,151 @@ list["unlinkDiscord"] = new SimplePopup(
|
|||
},
|
||||
() => {
|
||||
//
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
list["generateApeKey"] = new SimplePopup(
|
||||
"generateApeKey",
|
||||
"text",
|
||||
"Generate new key",
|
||||
[
|
||||
{
|
||||
placeholder: "Name",
|
||||
initVal: "",
|
||||
},
|
||||
],
|
||||
"",
|
||||
"Generate",
|
||||
async (_thisPopup, name) => {
|
||||
Loader.show();
|
||||
const response = await Ape.apeKeys.generate(name, false);
|
||||
Loader.hide();
|
||||
|
||||
if (response.status !== 200) {
|
||||
return Notifications.add(
|
||||
"Failed to generate key: " + response.message,
|
||||
-1
|
||||
);
|
||||
} else {
|
||||
const data = response.data;
|
||||
list["viewApeKey"].show([data.apeKey]);
|
||||
const snap = DB.getSnapshot();
|
||||
if (snap.apeKeys) {
|
||||
snap.apeKeys[data.apeKeyId] = data.apeKeyDetails;
|
||||
DB.setSnapshot(snap);
|
||||
}
|
||||
}
|
||||
},
|
||||
() => {
|
||||
//
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
list["viewApeKey"] = new SimplePopup(
|
||||
"viewApeKey",
|
||||
"text",
|
||||
"Ape Key",
|
||||
[
|
||||
{
|
||||
type: "textarea",
|
||||
disabled: true,
|
||||
placeholder: "Key",
|
||||
initVal: "",
|
||||
},
|
||||
],
|
||||
"This is your new Ape Key. Please keep it safe. You will only see it once!",
|
||||
"Close",
|
||||
(_thisPopup) => {
|
||||
ApeKeysPopup.show();
|
||||
},
|
||||
(_thisPopup) => {
|
||||
_thisPopup.inputs[0].initVal = _thisPopup.parameters[0];
|
||||
},
|
||||
(_thisPopup) => {
|
||||
_thisPopup.canClose = false;
|
||||
$("#simplePopup textarea").css("height", "110px");
|
||||
$("#simplePopup .button").addClass("hidden");
|
||||
setTimeout(() => {
|
||||
_thisPopup.canClose = true;
|
||||
$("#simplePopup .button").removeClass("hidden");
|
||||
}, 3000);
|
||||
}
|
||||
);
|
||||
|
||||
list["deleteApeKey"] = new SimplePopup(
|
||||
"deleteApeKey",
|
||||
"text",
|
||||
"Delete Ape Key",
|
||||
[],
|
||||
"Are you sure?",
|
||||
"Delete",
|
||||
async (_thisPopup) => {
|
||||
Loader.show();
|
||||
const response = await Ape.apeKeys.delete(_thisPopup.parameters[0]);
|
||||
Loader.hide();
|
||||
|
||||
if (response.status !== 200) {
|
||||
return Notifications.add("Failed to delete key: " + response.message, -1);
|
||||
}
|
||||
|
||||
Notifications.add("Key deleted", 1);
|
||||
const snap = DB.getSnapshot();
|
||||
if (snap.apeKeys) {
|
||||
delete snap.apeKeys[_thisPopup.parameters[0]];
|
||||
DB.setSnapshot(snap);
|
||||
}
|
||||
ApeKeysPopup.show();
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
list["editApeKey"] = new SimplePopup(
|
||||
"editApeKey",
|
||||
"text",
|
||||
"Edit Ape Key",
|
||||
[
|
||||
{
|
||||
placeholder: "Name",
|
||||
initVal: "",
|
||||
},
|
||||
],
|
||||
"",
|
||||
"Edit",
|
||||
async (_thisPopup, input) => {
|
||||
Loader.show();
|
||||
const response = await Ape.apeKeys.update(_thisPopup.parameters[0], {
|
||||
name: input,
|
||||
});
|
||||
Loader.hide();
|
||||
|
||||
if (response.status !== 200) {
|
||||
return Notifications.add("Failed to update key: " + response.message, -1);
|
||||
}
|
||||
|
||||
Notifications.add("Key updated", 1);
|
||||
const snap = DB.getSnapshot();
|
||||
if (snap.apeKeys) {
|
||||
snap.apeKeys[_thisPopup.parameters[0]].name = input;
|
||||
DB.setSnapshot(snap);
|
||||
}
|
||||
ApeKeysPopup.show();
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
},
|
||||
(_thisPopup) => {
|
||||
//
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -726,6 +934,20 @@ $(".pageSettings #deleteAccount").on("click", () => {
|
|||
list["deleteAccount"].show();
|
||||
});
|
||||
|
||||
$("#apeKeysPopup .generateApeKey").on("click", () => {
|
||||
list["generateApeKey"].show();
|
||||
});
|
||||
|
||||
$(document).on("click", "#apeKeysPopup table tbody tr .button.delete", (e) => {
|
||||
const keyId = $(e.target).closest("tr").attr("keyId") as string;
|
||||
list["deleteApeKey"].show([keyId]);
|
||||
});
|
||||
|
||||
$(document).on("click", "#apeKeysPopup table tbody tr .button.edit", (e) => {
|
||||
const keyId = $(e.target).closest("tr").attr("keyId") as string;
|
||||
list["editApeKey"].show([keyId]);
|
||||
});
|
||||
|
||||
$(document).on(
|
||||
"click",
|
||||
".pageSettings .section.fontFamily .button.custom",
|
||||
|
|
13
frontend/src/scripts/types/types.d.ts
vendored
13
frontend/src/scripts/types/types.d.ts
vendored
|
@ -241,6 +241,18 @@ declare namespace MonkeyTypes {
|
|||
hash?: string;
|
||||
}
|
||||
|
||||
type ApeKey = {
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
createdOn: number;
|
||||
modifiedOn: number;
|
||||
lastUsedOn: number;
|
||||
};
|
||||
|
||||
interface ApeKeys {
|
||||
[key: string]: ApeKey;
|
||||
}
|
||||
|
||||
interface Config {
|
||||
theme: string;
|
||||
themeLight: string;
|
||||
|
@ -403,6 +415,7 @@ declare namespace MonkeyTypes {
|
|||
quoteMod?: boolean;
|
||||
discordId?: string;
|
||||
config?: Config;
|
||||
apeKeys?: ApeKeys;
|
||||
}
|
||||
|
||||
type PartialRecord<K extends keyof any, T> = {
|
||||
|
|
|
@ -10,6 +10,10 @@ textarea {
|
|||
font-family: var(--font);
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
input[type="range"] {
|
||||
-webkit-appearance: none;
|
||||
padding: 0;
|
||||
|
|
|
@ -522,6 +522,112 @@
|
|||
}
|
||||
}
|
||||
|
||||
#apeKeysPopup {
|
||||
background: var(--bg-color);
|
||||
border-radius: var(--roundness);
|
||||
padding: 2rem;
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
width: 1000px;
|
||||
max-width: calc(100vw - 4rem);
|
||||
// height: 100%;
|
||||
// max-height: 40rem;
|
||||
min-height: 18rem;
|
||||
overflow-y: scroll;
|
||||
grid-template-rows: max-content auto;
|
||||
align-items: baseline;
|
||||
gap: 1rem;
|
||||
|
||||
.top {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
.title {
|
||||
font-size: 1.5rem;
|
||||
color: var(--sub-color);
|
||||
}
|
||||
.button {
|
||||
padding: 0.4rem 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.keyButtons {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
gap: 1rem;
|
||||
.button {
|
||||
width: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
|
||||
tr td:first-child {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tr.me {
|
||||
td {
|
||||
color: var(--main-color);
|
||||
// font-weight: 900;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.5rem 0.5rem;
|
||||
}
|
||||
|
||||
thead {
|
||||
color: var(--sub-color);
|
||||
font-size: 0.75rem;
|
||||
|
||||
td {
|
||||
padding: 0.5rem;
|
||||
background: var(--bg-color);
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
color: var(--text-color);
|
||||
|
||||
tr:nth-child(odd) td {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
tfoot {
|
||||
td {
|
||||
padding: 1rem 0.5rem;
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
bottom: -5px;
|
||||
background: var(--bg-color);
|
||||
color: var(--main-color);
|
||||
z-index: 4;
|
||||
}
|
||||
}
|
||||
|
||||
tr {
|
||||
td:first-child {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
td:last-child {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#quoteApprovePopup {
|
||||
background: var(--bg-color);
|
||||
border-radius: var(--roundness);
|
||||
|
|
|
@ -551,6 +551,30 @@
|
|||
<div id="submitQuoteButton" class="button">Submit</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="apeKeysPopupWrapper" class="hidden popupWrapper">
|
||||
<div id="apeKeysPopup" mode="">
|
||||
<div class="top">
|
||||
<div class="title">Ape Keys</div>
|
||||
<div class="button generateApeKey">
|
||||
<i class="fas fa-plus"></i>
|
||||
Generate new key
|
||||
</div>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td width="1px">active</td>
|
||||
<td>name</td>
|
||||
<td>created on</td>
|
||||
<td>modified on</td>
|
||||
<td>last used on</td>
|
||||
<td width="1px"></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="quoteReportPopupWrapper" class="popupWrapper hidden">
|
||||
<div id="quoteReportPopup" mode="">
|
||||
<div class="title">Report a Quote</div>
|
||||
|
@ -4115,6 +4139,22 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section apeKeys needsAccount">
|
||||
<h1>ape keys</h1>
|
||||
<div class="text">
|
||||
Generate Ape Keys to access certain API endpoints.
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<div
|
||||
class="button"
|
||||
id="showApeKeysPopup"
|
||||
tabindex="0"
|
||||
onclick="this.blur();"
|
||||
>
|
||||
open
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section resetSettings">
|
||||
<h1>reset settings</h1>
|
||||
<div class="text">
|
||||
|
|
Loading…
Reference in a new issue