Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto export snapshots #1047

Merged
merged 21 commits into from
Jun 5, 2023
Merged

Auto export snapshots #1047

merged 21 commits into from
Jun 5, 2023

Conversation

gotjoshua
Copy link
Contributor

work in progress, very interested in feedback

i want to have snapshots show up in my logseq graph automatically... so i hacked together this mvp

@mbnuqw i really dig the architecture... very easy to dive into your code (mostly ; -)

@mbnuqw
Copy link
Owner

mbnuqw commented May 24, 2023

Thank you for starting work on it! It's an implementation of #876 (if I'm not mistaken), and I'll merge it when it's done.

A few first thoughts:

  • Permission "downloads" should be optional, but since this PR is huge by itself I can do that myself after merge
  • Configuration of markdown format (nested list/only headers), probably should be moved to a different PR

@gotjoshua
Copy link
Contributor Author

Cool. Glad you're into it.
Yeah it's a partial solution for #876
Good call about the mark down indentation style belonging in a separate pr...

I will also need feedback about the refactoring i did... Moving some functions to the actions file that were previously in the Vue file and splitting prepare and export.

I'll also need an explanation of what happens in minify snapshot, cuz it kept me very busy trying to understand what it means for a tab to equal -1

@mbnuqw
Copy link
Owner

mbnuqw commented May 25, 2023

refactoring

Refactoring is ok. Cleaning up of the snapshots.vue was planned, but I always procrastinate on such tasks :)

Meaning of the "-1" values in snapshots

It means that the value is the same as in the previous snapshot (SnapStoreMode.Unchanged). Visual example:

Snapshot1 Snapshot2 Snapshot3 Normalized Snapshot3
tab1 -1 -1 tab1
tab2 tab4 -1 tab4
tab3 -1 tab5 tab5

Call the Snapshots.getNormalizedSnapshot() when you need NormalizedSnapshot. I also just found that Snapshots.getNormalizedSnapshot incorrectly handle some cases - when the previous snapshot is not found it should return undefined and we need to show error message to user (but I'll fix this later).

Also, please, use prettier: npx prettier -w src/services/snapshots.actions.ts, npx prettier -w src/page.setup/components/snapshots.vue, etc...

@gotjoshua
Copy link
Contributor Author

gotjoshua commented May 25, 2023

Also, please, use prettier: npx prettier -w src/services/snapshots.actions.ts, npx prettier -w src/page.setup/components/snapshots.vue, etc...

should i take time to get this happening automatically on save via eslint? or you prefer the manual step?

also, npx prettier -w ./src/ also changes some html files that i didn't touch, do you prefer to keep them unpretty? or should i include them in the final PR?

@gotjoshua
Copy link
Contributor Author

gotjoshua commented May 25, 2023

incorrectly handle some cases

ok, maybe i ran into some of those situations, but i anyway managed to work around them by calling auto export before the minification...

and many thanks for the explanations and collaboration!

@mbnuqw
Copy link
Owner

mbnuqw commented May 25, 2023

prettier

I meant to selectively run prettier only for changed files, but never mind, I'll setup a Github action to automate this on PR, so you don't need to run prettier manually. (I'll also update .prettierignore with html files).

and many thanks for the explanations and collaboration!

thank You for spending your time on this

@gotjoshua
Copy link
Contributor Author

Good call about the mark down indentation style belonging in a separate pr...

i do agree that it might have been better, but it is not so easy for me to revert those changes line by line.

How important is it for you @mbnuqw ?

Do you like the feature idea in general? (i find it really nice for pasting or importing into nested knowledge tools like Logseq)

@gotjoshua
Copy link
Contributor Author

do you have any time for an interim code review?

features are basically working now, and I'll take some more time to clean up and review over the weekend.

@mbnuqw
Copy link
Owner

mbnuqw commented Jun 1, 2023

Sorry for delay.

i do agree that it might have been better, but it is not so easy for me to revert those changes line by line.
How important is it for you @mbnuqw ?

Not much, leave the features as they are.

Do you like the feature idea in general?

Yes, and it already was planned (but after v5 release), so it's good to have it implemented earlier.

Testing:

Possibly wrong indent in md output with "Tree Friendly MD (add extra bullets for windows and tabs)":

# Data/time
  - ## Window 1
  - Tab 1 (pinned)
  - Tab 2 (pinned)
    - ### Panel 1
      - Tab 3
    - ### Panel 2
      - Tab 4

It looks like Panel 1 is sub-element of the last pinned tab. What if we use this structure?:

# Data/time
- ## Window 1
  - ### Pinned tabs
    - Tab 1 (pinned)
    - Tab 2 (pinned)
  - ### Panel 1
    - Tab 3
  - ### Panel 2
    - Tab 4

Auto-export doesn't work with an empty path ("Path to Export to (relative to downloads)").

It should have the default value ("./" or maybe "./Snapshots" folder).

Firefox always asks (if configured in FF settings) where to save for auto-created snapshot.

It steals focus and will annoy users. We should use saveAs: false, in browser.downloads.download for auto-exported snapshots.

"json" and "both" format options doesn't work

const dt = new Date(ms)
let time = `${dt.getHours()}`.padStart(2, '0')
time += delimiter + `${dt.getMinutes()}`.padStart(2, '0')
if (min) time += delimiter + `${dt.getMinutes()}`.padStart(2, '0')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove min argument.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd like to keep it for a later option i have in mind (if its harmless enough for you)

@@ -1,6 +1,7 @@
import { SETTINGS_OPTIONS } from '../defaults'

export interface SettingsState {
[x: string]: any
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove [x: string]: any

import { Containers } from './containers'
import { DEFAULT_CONTAINER_ID } from 'src/defaults/containers'
import { PanelType } from 'src/types/sidebar'
import { ItemInfo } from 'src/types/tabs'
import { Info } from './info'
import { createDefaultSidebarConfig, getSidebarConfigFromV4 } from './sidebar-config'
import { Favicons } from './favicons'
import { nextTick } from 'vue'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove import { nextTick } from 'vue' (b/c it's unused, and I'm trying to import view lib only in components and top-lvl scripts like sidebar.ts or setup.ts)

waiting = await Promise.allSettled([
browser.storage.local.get<Stored>(['sidebar', 'containers', 'snapshots']),
Tabs.updateBgTabsTreeData(),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this change (I guess it's a debugging, but just to be sure)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think i added that, rather just moved it from the old location, I'll try with and without it... And remove if not needed

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial code:

    waiting = await Promise.allSettled([
      browser.storage.local.get<Stored>(['sidebar', 'containers', 'snapshots']),
      Tabs.updateBgTabsTreeData(),
    ])

PR:

    console.log('updateBgTabsTreeData')
    await Tabs.updateBgTabsTreeData(), console.log('getting store')
    waiting = await Promise.allSettled([
      browser.storage.local.get<Stored>(['sidebar', 'containers', 'snapshots']),
    ])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this actally better in "parallel" in the allSettled array below? or ok to do it first?

export async function exportSnapshot(snapshot: Snapshot) {
const prepared = await prepareExport(snapshot)
if (!prepared || !browser?.downloads)
return console.warn('failed attempt to export snapshot', { snapshot, prepared, browser })
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use internal Logs.warn('Snapshots.exportSnapshot: Cannot export snapshot')

@@ -467,7 +506,7 @@ async function adaptTabsPanels(snapshot: NormalizedSnapshot): Promise<void> {
}

for (const storedId of stored.sidebar.nav) {
const storedPanel = stored.sidebar.panels[storedId]
const storedPanel = stored.sidebar?.panels?.[storedId]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same


let panelState = panelsById[tab.panelId]
if (!panelState) {
let panelConfig = snapshot.sidebar?.panels?.[tab.panelId]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for optional chaining (b/c type is NormilizedSnapshot)

@@ -683,7 +827,8 @@ export function convertFromV4(oldSnapshots: Snapshot_v4[]): Snapshot[] {

// Check panel
if (snapTab.panelId !== -1) {
const panelConf = snapshot.sidebar.panels[snapTab.panelId]
const panelConf = snapshot.sidebar?.panels?.[snapTab.panelId]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to opt chaining b/c snapshot is NormilizedSnapshot and sidebar is SidebarConfig

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌🙏


// if(!parsed)return
const { id, time, containers, sidebar, tabs } = snapshot //parsed
const normSnapshot = { id, time, containers, sidebar, tabs }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const normSnapshot is not NormalizedSnapshot and that may cause issues in convertToMarkdown fn. It's better to use NormalizedSnapshot type instead of Snapshot | SnapshotState and update:

  • exportSnapshot(...) to exportSnapshot(snapshot: NormalizedSnapshot)
  • in createSnapshot(...) fn, pass a NormalizedSnapshot- compatible type instead of the Snapshot to the exportSnapshot():
  if (Settings.state.snapAutoExport) {
    void exportSnapshot(currentSnapshot)
  }

with

  if (Settings.state.snapAutoExport) {
    exportSnapshot({
      id: currentSnapshot.id,
      time: currentSnapshot.time,
      containers: stored.containers,
      sidebar: stored.sidebar,
      tabs,
    })
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return { id, time, containers, sidebar, tabs, jsonFile, mdFile }
}

export async function getMostRecentSnapshot() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getMostRecentSnapshot, getMostRecentSnapshotMd are not used, remove?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i thought i would need them, and still might if we want to decouple timing of snapshot creation and export.
i can remove them for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gotjoshua
Copy link
Contributor Author

What if we use this structure

Looks great

Thanks for the detailed review!

Looking forward to get this ready to merge...

@gotjoshua
Copy link
Contributor Author

> - ## Window 1
>   - ### Pinned tabs
>     - Tab 1 (pinned)
>     - Tab 2 (pinned)
>   - ### Panel 1
>     - Tab 3

just started on this adjustment and realized that technically the pinned tabs "live" within the panels.
so when i switch panels the pinned tabs switch to the pinned tabs from the other panel

this indicates a structure like this may be better:

- ## Window 1
  - ### Panel 1 Base
    - Pinned
      - Tab 1 (pinned)
      - Tab 2 (pinned)
    - non-pinned Tab 3 ...
 ** OR **
  - ### Panel 2 - Media
    - Tab 1 (pinned)
    - Tab 2 (pinned)
    - non-pinned Tab 3 ...

notice that the pinned tabs are different for each panel:
Screenshot from 2023-06-04 12-03-07
Screenshot from 2023-06-04 12-02-35

@mbnuqw
Copy link
Owner

mbnuqw commented Jun 4, 2023

Hm... you're right, it would be better to align markdown rendering with settings (pinned tabs at panel-level or at global-level - "Pinned tabs position" setting).

We need to change the way how snapshot is created to distinguish the global pinned tabs (e.g. with tab.panelId === -1) and per-panel (tab.panelId === "PANEL_ID"), because right now it's not possible to get the type of pinned tab. I can do this after this PR will be merged.

@mbnuqw
Copy link
Owner

mbnuqw commented Jun 4, 2023

- ## Window 1
  - ### Panel 1 Base
    - Pinned
      - Tab 1 (pinned)
      - Tab 2 (pinned)
    - non-pinned Tab 3 ...
 ** OR **
  - ### Panel 2 - Media
    - Tab 1 (pinned)
    - Tab 2 (pinned)
    - non-pinned Tab 3 ...

Both variants are ok, but the second is better b/c we don't need to translate to other languages "Pinned" (considering that the pinned tabs are marked with 📌).

@gotjoshua
Copy link
Contributor Author

the second is better

Also semantically feels better to me...

@gotjoshua
Copy link
Contributor Author

We need to change the way how snapshot is created to distinguish

great that you can do that after merge!

it works now (onezoomin@73b62c0)

image

but feels rather hackish to remerge the pinned tabs that belong in the panels.

@gotjoshua gotjoshua changed the title wip Auto export snapshots Auto export snapshots Jun 4, 2023
@gotjoshua
Copy link
Contributor Author

gotjoshua commented Jun 4, 2023

I ran out of time for this week...

if you want to finish these up, please feel free... otherwise i'll try to squeeze in some time later next week!

  • Auto-export doesn't work with an empty path ("Path to Export to (relative to downloads)").
    • It should have the default value ("./" or maybe "./Snapshots" folder).
  • Firefox always asks (if configured in FF settings) where to save for auto-created snapshot.
    • It steals focus and will annoy users. We should use saveAs: false, in browser.downloads.download for auto-exported snapshots.
  • "json" and "both" format options doesn't work

@mbnuqw
Copy link
Owner

mbnuqw commented Jun 5, 2023

Alright, thank you for your time. I'll try to finish this and publish a new release soon.

@mbnuqw mbnuqw marked this pull request as ready for review June 5, 2023 11:57
@mbnuqw mbnuqw merged commit 35a6223 into mbnuqw:v5 Jun 5, 2023
@gotjoshua
Copy link
Contributor Author

I'll try to finish this

🙏

1 similar comment
@gotjoshua
Copy link
Contributor Author

I'll try to finish this

🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants