Skip to content

Commit 7aba6d9

Browse files
feat: replace pinning with import to mfs (#997)
This changes the way IPFS content is kept around. Instead of using low level pins we copy the item to MFS, unifying experience to match recent changes in ipfs-webui v2.12: https://github.com/ipfs/ipfs-webui/releases/v2.12.0 and ipfs-desktop v0.15.0: https://github.com/ipfs/ipfs-desktop/releases/tag/v0.15.0 This also removed page-action, because it was Firefox-specific feature and made maintenance and testing more difficult (now we have same UX in all browsers). Closes #742 Closes #888 Closes ipfs/ipfs-gui#91 Co-authored-by: Jessica Schilling <[email protected]>
1 parent 72fca61 commit 7aba6d9

File tree

17 files changed

+78
-257
lines changed

17 files changed

+78
-257
lines changed

add-on/_locales/en/messages.json

+9-21
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@
8383
"message": "Enable/disable all IPFS integrations on $1.",
8484
"description": "A menu item tooltip in Browser Action pop-up (panel_activeTabSiteIntegrationsToggleTooltip)"
8585
},
86-
"panel_pinCurrentIpfsAddress": {
87-
"message": "Pin IPFS Resource",
88-
"description": "A menu item in Browser Action pop-up (panel_pinCurrentIpfsAddress)"
86+
"panel_importCurrentIpfsAddress": {
87+
"message": "Import to Files on My Node",
88+
"description": "A menu item in Browser Action pop-up (panel_importCurrentIpfsAddress)"
8989
},
90-
"panel_pinCurrentIpfsAddressTooltip": {
91-
"message": "Pin this page's IPFS resources to your node to have a local copy that's available offline and never thrown away.",
92-
"description": "A menu item tooltip in Browser Action pop-up (panel_pinCurrentIpfsAddressTooltip)"
90+
"panel_importCurrentIpfsAddressTooltip": {
91+
"message": "Import this tab's IPFS resources to your Files to have a persistent local copy that's available offline and never thrown away.",
92+
"description": "A menu item tooltip in Browser Action pop-up (panel_importCurrentIpfsAddressTooltip)"
9393
},
9494
"panelCopy_currentIpnsAddress": {
9595
"message": "Copy IPNS Path",
@@ -195,21 +195,9 @@
195195
"message": "Copied",
196196
"description": "A title of system notification (notify_copiedTitle)"
197197
},
198-
"notify_pinnedIpfsResourceTitle": {
199-
"message": "IPFS Resource Pinned",
200-
"description": "A title of system notification (notify_pinnedIpfsResourceTitle)"
201-
},
202-
"notify_unpinnedIpfsResourceTitle": {
203-
"message": "Removed IPFS Pin",
204-
"description": "A title of system notification (notify_unpinnedIpfsResourceTitle)"
205-
},
206-
"notify_pinErrorTitle": {
207-
"message": "Error Pinning IPFS Resource",
208-
"description": "A title of system notification (notify_pinErrorTitle)"
209-
},
210-
"notify_unpinErrorTitle": {
211-
"message": "Error Removing IPFS Pin",
212-
"description": "A title of system notification (notify_unpinErrorTitle)"
198+
"notify_fileCpImportErrorTitle": {
199+
"message": "Error while importing IPFS Resource",
200+
"description": "A title of system notification (notify_fileCpImportErrorTitle)"
213201
},
214202
"notify_apiOnlineTitle": {
215203
"message": "IPFS API is Online",

add-on/manifest.firefox.json

-7
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@
1111
"strict_min_version": "68.0"
1212
}
1313
},
14-
"page_action": {
15-
"default_icon": {
16-
"128": "icons/ipfs-logo-off.svg"
17-
},
18-
"default_title": "__MSG_pageAction_titleNonIpfs__",
19-
"default_popup": "dist/popup/page-action/index.html"
20-
},
2114
"permissions": [
2215
"<all_urls>",
2316
"idle",

add-on/src/landing-pages/welcome/page.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ const renderInstallSteps = (i18n, isIpfsOnline) => {
100100
</svg>
101101
`
102102

103-
const optionsUrl = browser.extension.getURL(optionsPage)
103+
const optionsUrl = browser.runtime.getURL(optionsPage)
104104
return html`
105105
<div class="w-80 mt0 flex flex-column transition-all ${stateUnknown && 'state-unknown'}">
106106
<div class="mb4 flex flex-column justify-center items-center">

add-on/src/lib/ipfs-client/brave.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,8 @@ async function activationUiCleanup (browser) {
255255
})
256256
log('[activation ui cleanup] Brave gateway is up, cleaning up')
257257

258-
const welcomePageUrl = browser.extension.getURL(welcomePage)
259-
const optionsPageUrl = browser.extension.getURL(optionsPage)
258+
const welcomePageUrl = browser.runtime.getURL(welcomePage)
259+
const optionsPageUrl = browser.runtime.getURL(optionsPage)
260260
// we are unable to query ipfs:// directly due to reasons mentioned in 'closeIpfsTab'
261261
// so we make quick pass over all tabs and check welcome and options while at it.
262262
for (const tab of await browser.tabs.query({})) {

add-on/src/lib/ipfs-companion.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const createDnslinkResolver = require('./dnslink')
1717
const { createRequestModifier } = require('./ipfs-request')
1818
const { initIpfsClient, destroyIpfsClient } = require('./ipfs-client')
1919
const { braveNodeType, useBraveEndpoint, releaseBraveEndpoint } = require('./ipfs-client/brave')
20-
const { createIpfsImportHandler, formatImportDirectory } = require('./ipfs-import')
20+
const { createIpfsImportHandler, formatImportDirectory, browserActionFilesCpImportCurrentTab } = require('./ipfs-import')
2121
const createNotifier = require('./notifier')
2222
const createCopier = require('./copier')
2323
const createInspector = require('./inspector')
@@ -234,6 +234,7 @@ module.exports = async function init () {
234234

235235
const BrowserActionMessageHandlers = {
236236
notification: (message) => notify(message.title, message.message),
237+
[browserActionFilesCpImportCurrentTab]: () => ipfsImportHandler.filesCpImportCurrentTab(browser),
237238
[contextMenuViewOnGateway]: inspector.viewOnGateway,
238239
[contextMenuCopyCanonicalAddress]: copier.copyCanonicalAddress,
239240
[contextMenuCopyCidAddress]: copier.copyCidAddress,

add-on/src/lib/ipfs-import.js

+43-4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ log.error = debug('ipfs-companion:import:error')
88
const browser = require('webextension-polyfill')
99

1010
const { redirectOptOutHint } = require('./ipfs-request')
11+
const { ipfsContentPath } = require('./ipfs-path')
12+
13+
module.exports.browserActionFilesCpImportCurrentTab = 'browserActionFilesCpImportCurrentTab'
1114

1215
module.exports.createIpfsImportHandler = (getState, getIpfs, ipfsPathValidator, runtime, copier) => {
13-
const { resolveToPublicUrl } = ipfsPathValidator
16+
const {
17+
resolveToPublicUrl,
18+
resolveToCid
19+
} = ipfsPathValidator
1420
const ipfsImportHandler = {
1521
getIpfsPathAndNativeAddress (cid) {
1622
const state = getState()
@@ -33,9 +39,8 @@ module.exports.createIpfsImportHandler = (getState, getIpfs, ipfsPathValidator,
3339

3440
async openFilesAtWebUI (mfsPath) {
3541
const state = getState()
36-
await browser.tabs.create({
37-
url: `${state.webuiRootUrl}#/files${mfsPath}`
38-
})
42+
const url = `${state.webuiRootUrl}#/files${mfsPath}`
43+
await browser.tabs.create({ url })
3944
},
4045

4146
async copyImportResultsToFiles (results, importDir) {
@@ -82,7 +87,41 @@ module.exports.createIpfsImportHandler = (getState, getIpfs, ipfsPathValidator,
8287
}
8388
}
8489
}
90+
},
91+
92+
async filesCpImportCurrentTab (browser) {
93+
try {
94+
const {
95+
copyShareLink,
96+
preloadFilesAtPublicGateway,
97+
openFilesAtWebUI
98+
} = this
99+
const currentTab = await browser.tabs.query({ active: true, currentWindow: true }).then(tabs => tabs[0])
100+
const importDir = module.exports.formatImportDirectory(getState().importDir)
101+
const ipfs = getIpfs()
102+
const contentPath = ipfsContentPath(currentTab.url, { keepURIParams: false })
103+
const pathSegments = contentPath.split('/').filter(Boolean)
104+
const namedImport = typeof pathSegments[2] !== 'undefined'
105+
const resolvedCid = await resolveToCid(contentPath)
106+
107+
// best-effort name based on last path segment, or IPNS root
108+
const name = namedImport
109+
? pathSegments.slice(-1)
110+
: `${pathSegments[0] === 'ipns' ? pathSegments[1] : 'unnamed'}_${resolvedCid.slice(-4)}`
111+
112+
// import to mfs
113+
await ipfs.files.mkdir(importDir, { parents: true })
114+
await ipfs.files.cp(`/ipfs/${resolvedCid}`, `${importDir}${name}`)
115+
await openFilesAtWebUI(importDir)
116+
117+
// create fake ipfs.add results, so we can reuse code from quick-import feature
118+
const { cid } = await ipfs.files.stat(importDir, { hash: true })
119+
const results = [{ path: '', cid }, { path: name, cid: resolvedCid }]
120+
await copyShareLink(results)
121+
await preloadFilesAtPublicGateway(results)
122+
} catch (e) { log.error('unexpected error during filesCpImportCurrentTab', e) }
85123
}
124+
86125
}
87126
return ipfsImportHandler
88127
}

add-on/src/lib/ipfs-proxy/request-access.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function createRequestAccess (browser, screen) {
1919
// TODO: cleanup so below stub is not needed
2020
permissions = Array.isArray(permissions) ? permissions : [permissions]
2121

22-
const url = browser.extension.getURL(opts.dialogPath || DIALOG_PATH)
22+
const url = browser.runtime.getURL(opts.dialogPath || DIALOG_PATH)
2323

2424
let dialogTabId
2525

add-on/src/lib/notifier.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function createNotifier (getState) {
2020
try {
2121
return await browser.notifications.create({
2222
type: 'basic',
23-
iconUrl: browser.extension.getURL('icons/ipfs-logo-on.svg'),
23+
iconUrl: browser.runtime.getURL('icons/ipfs-logo-on.svg'),
2424
title: title,
2525
message: message
2626
})

add-on/src/options/forms/experiments-form.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ function experimentsForm ({
108108
${browser.i18n.getMessage('option_ipfsProxy_description')}
109109
<p>${ipfsProxy
110110
? html`
111-
<a class="link underline hover-aqua" href="${browser.extension.getURL('dist/pages/proxy-acl/index.html')}" target="_blank">
111+
<a class="link underline hover-aqua" href="${browser.runtime.getURL('dist/pages/proxy-acl/index.html')}" target="_blank">
112112
${browser.i18n.getMessage('option_ipfsProxy_link_manage_permissions')}
113113
</a>`
114114
: html`<del>${browser.i18n.getMessage('option_ipfsProxy_link_manage_permissions')}</del>`}

add-on/src/popup/browser-action/context-actions.js

+9-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const html = require('choo/html')
66
const navItem = require('./nav-item')
77
const navHeader = require('./nav-header')
88
const { sameGateway } = require('../../lib/ipfs-path')
9+
const { formatImportDirectory } = require('../../lib/ipfs-import')
910
const {
1011
contextMenuViewOnGateway,
1112
contextMenuCopyAddressAtPublicGw,
@@ -35,26 +36,22 @@ function contextActions ({
3536
currentTabPermalink = notReady,
3637
ipfsNodeType,
3738
isIpfsContext,
38-
isPinning,
39-
isUnPinning,
40-
isPinned,
4139
isIpfsOnline,
4240
isApiAvailable,
4341
onToggleSiteIntegrations,
4442
onViewOnGateway,
4543
onCopy,
46-
onPin,
47-
onUnPin
44+
importDir,
45+
onFilesCpImport
4846
}) {
4947
const activeCidResolver = active && isIpfsOnline && isApiAvailable && currentTabCid
50-
const activePinControls = active && isIpfsOnline && isApiAvailable
48+
const activeFilesCpImport = active && isIpfsOnline && isApiAvailable && !ipfsNodeType.startsWith('embedded')
5149
const isMutable = currentTabContentPath.startsWith('/ipns/')
5250
const activeViewOnGateway = (currentTab) => {
5351
if (!currentTab) return false
5452
const { url } = currentTab
5553
return !(url.startsWith('ip') || sameGateway(url, gwURLString) || sameGateway(url, pubGwURLString))
5654
}
57-
5855
const renderIpfsContextItems = () => {
5956
if (!isIpfsContext) return
6057
return html`<div>
@@ -100,11 +97,11 @@ function contextActions ({
10097
onClick: () => onCopy(contextMenuCopyRawCid)
10198
})}
10299
${navItem({
103-
text: browser.i18n.getMessage('panel_pinCurrentIpfsAddress'),
104-
title: browser.i18n.getMessage('panel_pinCurrentIpfsAddressTooltip'),
105-
disabled: !activePinControls,
106-
switchValue: (isPinned || isPinning) && !isUnPinning,
107-
onClick: isPinned ? onUnPin : onPin
100+
text: browser.i18n.getMessage('panel_importCurrentIpfsAddress'),
101+
title: browser.i18n.getMessage('panel_importCurrentIpfsAddressTooltip'),
102+
helperText: formatImportDirectory(importDir),
103+
disabled: !activeFilesCpImport,
104+
onClick: onFilesCpImport
108105
})}
109106
</div>
110107
`

add-on/src/popup/browser-action/page.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ const tools = require('./tools')
1212
module.exports = function browserActionPage (state, emit) {
1313
const onViewOnGateway = () => emit('viewOnGateway')
1414
const onCopy = (copyAction) => emit('copy', copyAction)
15-
const onPin = () => emit('pin')
16-
const onUnPin = () => emit('unPin')
15+
const onFilesCpImport = () => emit('filesCpImport')
1716

1817
const onQuickImport = () => emit('quickImport')
1918
const onOpenWebUi = () => emit('openWebUi', '/')
@@ -25,7 +24,7 @@ module.exports = function browserActionPage (state, emit) {
2524
const onToggleActive = () => emit('toggleActive')
2625

2726
const headerProps = Object.assign({ onToggleActive, onOpenPrefs, onOpenReleaseNotes, onOpenWelcomePage }, state)
28-
const activeTabActionsProps = Object.assign({ onViewOnGateway, onToggleSiteIntegrations, onCopy, onPin, onUnPin }, state)
27+
const activeTabActionsProps = Object.assign({ onViewOnGateway, onToggleSiteIntegrations, onCopy, onFilesCpImport }, state)
2928
const opsProps = Object.assign({ onQuickImport, onOpenWebUi, onToggleGlobalRedirect }, state)
3029

3130
return html`

0 commit comments

Comments
 (0)