message: Make tag storage a bit more safe
diff: @@ -39,26 +39,23 @@ export const itemTags: TagInfo[] = [
  { type: 'infuse', label: 'Tags.Infuse', hotkey: 'shift+4', icon: boltIcon }
  ];
  -/**
  - * An account-specific source of item info objects, keyed off instanceId.
  - */
  -export class ItemInfoSource {
  - constructor(readonly key: string, readonly infos: { [itemInstanceId: string]: DimItemInfo }) {}
  +class ItemInfo implements DimItemInfo {
  + constructor(
  + private itemKey: string,
  + private accountKey: string,
  + public tag?: TagValue,
  + public notes?: string
  + ) {}
  - infoForItem(hash: number, id: string): DimItemInfo {
  - const itemKey = `${hash}-${id}`;
  - const info = this.infos[itemKey];
  - const accountKey = this.key;
  - return {
  - ...info,
  save() {
  - return getInfos(accountKey).then((infos) => {
  - infos[itemKey] = _.omit(this, 'save');
  - if (_.isEmpty(infos[itemKey])) {
  - delete infos[itemKey];
  + return getInfos(this.accountKey).then((infos) => {
  + if (!this.tag && (!this.notes || this.notes.length === 0)) {
  + delete infos[this.itemKey];
  + } else {
  + infos[this.itemKey] = { tag: this.tag, notes: this.notes };
  }
  - store.dispatch(setTagsAndNotesForItem({ key: itemKey, info: infos[itemKey] }));
  - setInfos(accountKey, infos).catch((e) => {
  + store.dispatch(setTagsAndNotesForItem({ key: this.itemKey, info: infos[this.itemKey] }));
  + setInfos(this.accountKey, infos).catch((e) => {
  toaster.pop(
  'error',
  t('ItemInfoService.SaveInfoErrorTitle'),
  @@ -69,12 +66,23 @@ export class ItemInfoSource {
  });
  });
  }
  - };
  +}
  +
  +/**
  + * An account-specific source of item info objects, keyed off instanceId.
  + */
  +export class ItemInfoSource {
  + constructor(readonly key: string, readonly infos: { [itemInstanceId: string]: DimItemInfo }) {}
  +
  + infoForItem(hash: number, id: string): DimItemInfo {
  + const itemKey = `${hash}-${id}`;
  + const info = this.infos[itemKey];
  + return new ItemInfo(itemKey, this.key, info && info.tag, info && info.notes);
  }
  // Remove all item info that isn't in stores' items
  cleanInfos(stores: DimStore[]) {
  - if (!stores.length) {
  + if (!stores.length || stores.some((s) => s.items.length === 0)) {
  // don't accidentally wipe out notes
  return Promise.resolve();
  }
  @@ -82,6 +90,10 @@ export class ItemInfoSource {
  return getInfos(this.key).then((infos) => {
  const remain = {};
  + if (_.isEmpty(infos)) {
  + return Promise.resolve();
  + }
  +
  stores.forEach((store) => {
  store.items.forEach((item) => {
  const itemKey = `${item.hash}-${item.id}`;
  