Fix user labels storage issue.
This commit is contained in:
parent
e03fcec09c
commit
5fb151807e
|
@ -40,6 +40,9 @@
|
|||
"xo": {
|
||||
"extends": "@bauke/eslint-config",
|
||||
"prettier": true,
|
||||
"rules": {
|
||||
"no-await-in-loop": "off"
|
||||
},
|
||||
"space": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import debounce from "debounce";
|
||||
import {Component, render} from "preact";
|
||||
import {type Value} from "@holllo/webextension-storage";
|
||||
import {type UserLabelsData} from "../../storage/common.js";
|
||||
import {type UserLabelsData, saveUserLabels} from "../../storage/common.js";
|
||||
import {
|
||||
createElementFromString,
|
||||
isColorBright,
|
||||
|
@ -13,7 +12,7 @@ import {
|
|||
|
||||
type Props = {
|
||||
anonymizeUsernamesEnabled: boolean;
|
||||
userLabels: Value<UserLabelsData>;
|
||||
userLabels: UserLabelsData;
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
@ -70,7 +69,7 @@ export class UserLabelsFeature extends Component<Props, State> {
|
|||
|
||||
// Sort the labels by priority or alphabetically, so 2 labels with the same
|
||||
// priority will be sorted alphabetically.
|
||||
const sortedLabels = userLabels.value.sort((a, b): number => {
|
||||
const sortedLabels = userLabels.sort((a, b): number => {
|
||||
if (inTopicListing) {
|
||||
// If we're in the topic listing sort with highest priority first.
|
||||
if (a.priority !== b.priority) {
|
||||
|
@ -97,7 +96,7 @@ export class UserLabelsFeature extends Component<Props, State> {
|
|||
|
||||
const userLabels = sortedLabels.filter(
|
||||
(value) =>
|
||||
value.username === username &&
|
||||
value.username.toLowerCase() === username &&
|
||||
(onlyID === undefined ? true : value.id === onlyID),
|
||||
);
|
||||
|
||||
|
@ -192,9 +191,7 @@ export class UserLabelsFeature extends Component<Props, State> {
|
|||
if (this.state.target === target && !this.state.hidden) {
|
||||
this.hide();
|
||||
} else {
|
||||
const label = this.props.userLabels.value.find(
|
||||
(value) => value.id === id,
|
||||
);
|
||||
const label = this.props.userLabels.find((value) => value.id === id);
|
||||
if (label === undefined) {
|
||||
log(
|
||||
"User Labels: Tried to edit label with ID that could not be found.",
|
||||
|
@ -252,11 +249,11 @@ export class UserLabelsFeature extends Component<Props, State> {
|
|||
// If no ID is present then save a new label otherwise edit the existing one.
|
||||
if (id === undefined) {
|
||||
let newId = 1;
|
||||
if (userLabels.value.length > 0) {
|
||||
newId = userLabels.value.sort((a, b) => b.id - a.id)[0].id + 1;
|
||||
if (userLabels.length > 0) {
|
||||
newId = userLabels.sort((a, b) => b.id - a.id)[0].id + 1;
|
||||
}
|
||||
|
||||
userLabels.value.push({
|
||||
userLabels.push({
|
||||
color,
|
||||
id: newId,
|
||||
priority,
|
||||
|
@ -266,9 +263,9 @@ export class UserLabelsFeature extends Component<Props, State> {
|
|||
|
||||
this.addLabelsToUsernames(querySelectorAll(".link-user"), newId);
|
||||
} else {
|
||||
const index = userLabels.value.findIndex((value) => value.id === id);
|
||||
userLabels.value.splice(index, 1);
|
||||
userLabels.value.push({
|
||||
const index = userLabels.findIndex((value) => value.id === id);
|
||||
userLabels.splice(index, 1);
|
||||
userLabels.push({
|
||||
id,
|
||||
color,
|
||||
priority,
|
||||
|
@ -289,7 +286,7 @@ export class UserLabelsFeature extends Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
await userLabels.save();
|
||||
await saveUserLabels(userLabels);
|
||||
this.props.userLabels = userLabels;
|
||||
this.hide();
|
||||
};
|
||||
|
@ -303,7 +300,7 @@ export class UserLabelsFeature extends Component<Props, State> {
|
|||
}
|
||||
|
||||
const {userLabels} = this.props;
|
||||
const index = userLabels.value.findIndex((value) => value.id === id);
|
||||
const index = userLabels.findIndex((value) => value.id === id);
|
||||
if (index === undefined) {
|
||||
log(
|
||||
`User Labels: Tried to remove label with ID ${id} that could not be found.`,
|
||||
|
@ -316,8 +313,8 @@ export class UserLabelsFeature extends Component<Props, State> {
|
|||
value.remove();
|
||||
}
|
||||
|
||||
userLabels.value.splice(index, 1);
|
||||
await userLabels.save();
|
||||
userLabels.splice(index, 1);
|
||||
await saveUserLabels(userLabels);
|
||||
this.props.userLabels = userLabels;
|
||||
this.hide();
|
||||
};
|
||||
|
|
|
@ -102,7 +102,7 @@ async function initialize() {
|
|||
<AutocompleteFeature
|
||||
anonymizeUsernamesEnabled={anonymizeUsernamesEnabled}
|
||||
knownGroups={knownGroups.value}
|
||||
userLabels={userLabels.value}
|
||||
userLabels={userLabels}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
type UserLabel,
|
||||
fromStorage,
|
||||
Feature,
|
||||
saveUserLabels,
|
||||
} from "../storage/common.js";
|
||||
import "../scss/index.scss";
|
||||
import "../scss/user-label-editor.scss";
|
||||
|
@ -21,7 +22,7 @@ window.addEventListener("load", async () => {
|
|||
});
|
||||
|
||||
type Props = {
|
||||
userLabels: Value<UserLabelsData>;
|
||||
userLabels: UserLabelsData;
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
@ -37,7 +38,7 @@ class App extends Component<Props, State> {
|
|||
this.state = {
|
||||
hasUnsavedChanges: false,
|
||||
newLabelUsername: "",
|
||||
userLabels: props.userLabels.value,
|
||||
userLabels: props.userLabels,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -101,8 +102,8 @@ class App extends Component<Props, State> {
|
|||
};
|
||||
|
||||
saveUserLabels = () => {
|
||||
this.props.userLabels.value = this.state.userLabels;
|
||||
void this.props.userLabels.save();
|
||||
this.props.userLabels = this.state.userLabels;
|
||||
void saveUserLabels(this.props.userLabels);
|
||||
this.setState({hasUnsavedChanges: false});
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
.group {
|
||||
border: 1px solid var(--blue);
|
||||
overflow: scroll;
|
||||
padding: 16px;
|
||||
|
||||
h2 {
|
||||
|
@ -40,6 +41,7 @@
|
|||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
input {
|
||||
|
|
|
@ -45,6 +45,50 @@ export type UsernameColor = {
|
|||
|
||||
export type UsernameColorsData = UsernameColor[];
|
||||
|
||||
/**
|
||||
* Get all user labels from storage and combine them into a single array.
|
||||
*/
|
||||
export async function collectUserLabels(): Promise<UserLabelsData> {
|
||||
const storage = await browser.storage.sync.get();
|
||||
const userLabels = [];
|
||||
for (const [key, value] of Object.entries(storage)) {
|
||||
if (!key.startsWith(Feature.UserLabels)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
userLabels.push(JSON.parse(value as string) as UserLabel);
|
||||
}
|
||||
|
||||
return userLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all user labels to storage under individual keys.
|
||||
*
|
||||
* They are stored under individual keys so that we don't run into storage quota
|
||||
* limits. If it was stored under a single key we would only be able to fit
|
||||
* around 80-100 labels before hitting the limit.
|
||||
* @param userLabels The user labels array to save.
|
||||
*/
|
||||
export async function saveUserLabels(
|
||||
userLabels: UserLabelsData,
|
||||
): Promise<void> {
|
||||
const storage = await browser.storage.sync.get();
|
||||
for (const key of Object.keys(storage)) {
|
||||
if (!key.startsWith(Feature.UserLabels)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await browser.storage.sync.remove(key);
|
||||
}
|
||||
|
||||
for (const label of userLabels) {
|
||||
await browser.storage.sync.set({
|
||||
[`${Feature.UserLabels}-${label.id}`]: JSON.stringify(label),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const storageValues = {
|
||||
[Data.EnabledFeatures]: createValue({
|
||||
deserialize: (input) => new Set(JSON.parse(input) as Feature[]),
|
||||
|
@ -79,13 +123,8 @@ export const storageValues = {
|
|||
},
|
||||
storage: browser.storage.sync,
|
||||
}),
|
||||
[Feature.UserLabels]: createValue({
|
||||
deserialize: (input) => JSON.parse(input) as UserLabelsData,
|
||||
serialize: (input) => JSON.stringify(Array.from(input)),
|
||||
key: Feature.UserLabels,
|
||||
value: [],
|
||||
storage: browser.storage.sync,
|
||||
}),
|
||||
// eslint-disable-next-line unicorn/prefer-top-level-await
|
||||
[Feature.UserLabels]: collectUserLabels(),
|
||||
[Feature.UsernameColors]: createValue({
|
||||
deserialize: (input) => JSON.parse(input) as UsernameColorsData,
|
||||
serialize: (input) => JSON.stringify(Array.from(input)),
|
||||
|
|
Loading…
Reference in New Issue