Skip to content

Commit 887e53e

Browse files
committed
feat: replace pinning with import to mfs
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 and ipfs-desktop 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
1 parent 72fca61 commit 887e53e

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 at 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 resource 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)