diff --git a/.aegir.js b/.aegir.js new file mode 100644 index 0000000..8fa995d --- /dev/null +++ b/.aegir.js @@ -0,0 +1,79 @@ +/** @type {import('aegir').PartialOptions} */ +const options = { + lint: { + files: [ + 'src/**/*.ts', + 'src/**/*.tsx', + 'test/**/*.ts', + 'test/**/*.tsx', + ] + }, + build: { + bundle: false, + /** + * esbuild options: + */ + config: { + loader: { + '.js': 'jsx', + '.ts': 'ts', + '.tsx': 'tsx' + } + } + }, + test: { + build: false, // we trigger aegir build in package.json + files: [ + 'aegir-build/test/**/*.spec.js' + ], + before: ({runner}) => { + // if (runner === 'node') { + // process.exit(0) + // } + // // skip tests + } + }, + dependencyCheck: { + ignore: [ + 'tachyons', // we import tachyons in App.css + + // aegir dep-check doesn't check tsx files properly: + '@helia/mfs', + '@libp2p/devtools-metrics', + 'classnames', + 'helia', + 'ipfs-css', + 'qrcode.react', + 'react-circular-progressbar', + 'react-copy-to-clipboard', + 'react-dnd', + 'react-dnd-html5-backend', + 'react-dom', + 'react-helmet', + 'react-i18next', + 'react-loader-spinner', + 'react-modal', + '@multiformats/multiaddr-matcher', + 'blockstore-idb', + 'datastore-idb', + 'interface-blockstore', + 'interface-datastore', + + // error when testing without this dep + 'node-datachannel' + ], + productionIgnorePatterns: [ + '.storybook', + 'vite.config.ts', + 'test', + '**/*.stories.*', + 'dist', + 'aegir-build' + ], + developmentIgnorePatterns: [ + 'dist', + 'aegir-build' + ] + } +} +export default options diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 1678f05..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,52 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: cimg/node:lts - steps: - - checkout - - run: - command: npm ci - - run: - command: npm run build - - persist_to_workspace: - root: . - paths: - - build - - deploy: - docker: - - image: olizilla/ipfs-dns-deploy:latest - environment: - PROD_DOMAIN: share.ipfs.io - DEV_DOMAIN: dev.share.ipfs.io - BUILD_DIR: build - steps: - - attach_workspace: - at: /tmp/workspace - - run: - name: Deploy website to IPFS - command: | - pin_name="ipfs-share-files build $CIRCLE_BUILD_NUMBER" - - hash=$(pin-to-cluster.sh "$pin_name" /tmp/workspace/$BUILD_DIR) - - echo "Website added to IPFS: https://dweb.link/ipfs/$hash" - - # Update DNSlink for prod or dev domain - if [ "$CIRCLE_BRANCH" == "production" ] ; then - dnslink-dnsimple -d $PROD_DOMAIN -r _dnslink -l /ipfs/$hash - fi - if [ "$CIRCLE_BRANCH" == "main" ] ; then - dnslink-dnsimple -d $DEV_DOMAIN -r _dnslink -l /ipfs/$hash - fi - -workflows: - version: 2 - build-deploy: - jobs: - - build - - deploy: - context: ipfs-dns-deploy - requires: - - build diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 89219fe..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - parser: 'babel-eslint', - extends: ['react-app', 'standard', 'plugin:jsx-a11y/recommended'], - plugins: ['jsx-a11y'] -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3170d40 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,64 @@ +name: Build and Deploy + +# Run this workflow on push events to specific branches +on: + push: + branches: + - main + - production + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 'lts' + + - name: Install dependencies + run: npm ci + + - name: Build the project + run: npm run build + + - name: Persist build output + id: build_output + run: | + echo "::set-output name=build_dir::build" + + # Deploy job + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: ipfs-dns-deploy + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker + uses: docker/setup-buildx-action@v2 + + - name: Pull deployment image + run: docker pull olizilla/ipfs-dns-deploy:latest + + - name: Deploy website to IPFS + run: | + pin_name="ipfs-share-files build ${{ github.run_number }}" + + # Pin the build directory to IPFS + hash=$(docker run --rm -e BUILD_DIR=${{ steps.build_output.outputs.build_dir }} olizilla/ipfs-dns-deploy:latest pin-to-cluster.sh "$pin_name" /github/workspace/build) + + echo "Website added to IPFS: https://dweb.link/ipfs/$hash" + + # Update DNSlink for production or dev domain + if [ "${{ github.ref }}" == "refs/heads/production" ]; then + docker run --rm olizilla/ipfs-dns-deploy:latest dnslink-dnsimple -d share.ipfs.io -r _dnslink -l /ipfs/$hash + elif [ "${{ github.ref }}" == "refs/heads/main" ]; then + docker run --rm olizilla/ipfs-dns-deploy:latest dnslink-dnsimple -d dev.share.ipfs.io -r _dnslink -l /ipfs/$hash + fi diff --git a/.gitignore b/.gitignore index bb0bc84..12cfcd2 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,8 @@ build/ # Misc .DS_Store +dist +.vscode +src/icons +aegir-build +.coverage diff --git a/.storybook/addons.js b/.storybook/addons.js deleted file mode 100644 index c8456f4..0000000 --- a/.storybook/addons.js +++ /dev/null @@ -1,4 +0,0 @@ -import '@storybook/addon-actions/register' -import '@storybook/addon-links/register' -import '@storybook/addon-a11y/register' -import '@storybook/addon-knobs/register' diff --git a/.storybook/config.js b/.storybook/config.js deleted file mode 100644 index 4fe20c9..0000000 --- a/.storybook/config.js +++ /dev/null @@ -1,10 +0,0 @@ -import { configure } from '@storybook/react' -import '../src/App.css' - -const req = require.context('../src', true, /\.stories\.js$/) - -function loadStories() { - req.keys().forEach((filename) => req(filename)) -} - -configure(loadStories, module); diff --git a/.storybook/main.ts b/.storybook/main.ts new file mode 100644 index 0000000..cd1ebdb --- /dev/null +++ b/.storybook/main.ts @@ -0,0 +1,36 @@ +import type { StorybookConfig } from '@storybook/react-vite'; + +// TODO: fix storybook dev and build + +const config: StorybookConfig = { + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + + addons: [ + '@storybook/addon-links', + // '@storybook/addon-essentials', + '@storybook/addon-interactions', + '@storybook/addon-coverage', + '@chromatic-com/storybook' + ], + + framework: { + name: '@storybook/react-vite', + options: {}, + }, + + // async viteFinal(config) { + // // Merge custom configuration into the default config + // return mergeConfig(config, viteConfig); + // }, + // docs: {} + typescript: { + // reactDocgen: 'react-docgen-typescript' + reactDocgen: false + // reactDocgenTypescriptOptions: { + + // } + }, + + docs: {} +}; +export default config; diff --git a/.storybook/preview.ts b/.storybook/preview.ts new file mode 100644 index 0000000..629beb3 --- /dev/null +++ b/.storybook/preview.ts @@ -0,0 +1,17 @@ +import { type Preview } from '@storybook/react'; +// import { Buffer } from 'buffer' + +// globalThis.Buffer = Buffer + +// import CSS files +// import 'ipfs-css' +// import 'react-virtualized/styles.css' +// import 'tachyons' +// import '../src/components/loader/Loader.css' +// import '../src/components/object-info/LinksTable.css' + +const preview: Preview = { + tags: ['autodocs', 'autodocs', 'autodocs'] +}; + +export default preview; diff --git a/Makefile b/Makefile deleted file mode 100644 index 2d3efbc..0000000 --- a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -build: - npm --version - # Pin the npm version to 6.4.1 (as bundled with node 8.12) - # Using npx is a workaround for npm<5.6 not being able to self update - # See: https://github.com/ipfs/ci-websites/issues/3 - npx npm@5.6 i -g npm@6.4.1 - node --version - npm install - npm run lint - npm run build diff --git a/README.md b/README.md index 087fc72..25b8a45 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,32 @@ On the app side, translations are stored in [`public/locales`](./public/locales) To learn more about internationalization on the IPFS project as a whole, or contribute translations to other IPFS repos, check out [ipfs/i18n](https://github.com/ipfs/i18n). +## REFRESH - TODO + +### UI + +1. Update the "progress bar" circular progress bar to be a loading indicator for record publishing +1. Disable share buttons when: + * no listening webrtc address + * CID is not published +1. Remove protocol labs footer -> replace with "powered by Helia" +1. Show the users what is actually happening in the background: + * Finding closest peers + * asking them to publish our provider record + +### Functionality + +1. publish directory CID +1. Make sure that when share.ipfs.io link with CID deeplink is shared, that browser retrieval client can get the file. +1. On self:update, we need to check if the listening webrtc address has changed, and republish all "files" and "directory" if so. +1. Ability to remove individual files from share list +1. Fix downloading the files filename + +### debugging + +1. Add libp2p-devtools + + ## Contribute Contributions are more than welcome! Check out the [currently open issues](https://github.com/ipfs-shipyard/ipfs-share-files/issues) and start hacking on anything that sounds interesting. Issues are labeled with a variety of tags to help you find a good fit — you may wish to start with the [`help-wanted`](https://github.com/ipfs-shipyard/ipfs-share-files/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) tag. diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js deleted file mode 100644 index e9c1e74..0000000 --- a/config/webpack.config.prod.js +++ /dev/null @@ -1,378 +0,0 @@ -/* eslint-disable */ -// @remove-on-eject-begin -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -// @remove-on-eject-end -'use strict'; - -const autoprefixer = require('autoprefixer'); -const path = require('path'); -const webpack = require('webpack'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const ExtractTextPlugin = require('extract-text-webpack-plugin'); -const ManifestPlugin = require('webpack-manifest-plugin'); -const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); -const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin'); -const eslintFormatter = require('react-dev-utils/eslintFormatter'); -const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); -const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); -const paths = require('./paths'); -const getClientEnvironment = require('./env'); - -// Webpack uses `publicPath` to determine where the app is being served from. -// It requires a trailing slash, or the file assets will get an incorrect path. -const publicPath = paths.servedPath; -// Some apps do not use client-side routing with pushState. -// For these, "homepage" can be set to "." to enable relative asset paths. -const shouldUseRelativeAssetPaths = publicPath === './'; -// Source maps are resource heavy and can cause out of memory issue for large source files. -const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; -// `publicUrl` is just like `publicPath`, but we will provide it to our app -// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. -// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz. -const publicUrl = publicPath.slice(0, -1); -// Get environment variables to inject into our app. -const env = getClientEnvironment(publicUrl); - -// Assert this just to be safe. -// Development builds of React are slow and not intended for production. -if (env.stringified['process.env'].NODE_ENV !== '"production"') { - throw new Error('Production builds must have NODE_ENV=production.'); -} - -// Note: defined here because it will be used more than once. -const cssFilename = 'static/css/[name].[contenthash:8].css'; - -// ExtractTextPlugin expects the build output to be flat. -// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27) -// However, our output is structured with css, js and media folders. -// To have this structure working with relative paths, we have to use custom options. -const extractTextPluginOptions = shouldUseRelativeAssetPaths - ? // Making sure that the publicPath goes back to to build folder. - { publicPath: Array(cssFilename.split('/').length).join('../') } - : {}; - -// This is the production configuration. -// It compiles slowly and is focused on producing a fast and minimal bundle. -// The development configuration is different and lives in a separate file. -module.exports = { - // Don't attempt to continue if there are any errors. - bail: true, - // We generate sourcemaps in production. This is slow but gives good results. - // You can exclude the *.map files from the build during deployment. - devtool: shouldUseSourceMap ? 'source-map' : false, - // In production, we only want to load the polyfills and the app code. - entry: [require.resolve('./polyfills'), paths.appIndexJs], - output: { - // The build folder. - path: paths.appBuild, - // Generated JS file names (with nested folders). - // There will be one main bundle, and one file per asynchronous chunk. - // We don't currently advertise code splitting but Webpack supports it. - filename: 'static/js/[name].[chunkhash:8].js', - chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js', - // We inferred the "public path" (such as / or /my-project) from homepage. - publicPath: publicPath, - // Point sourcemap entries to original disk location (format as URL on Windows) - devtoolModuleFilenameTemplate: info => - path - .relative(paths.appSrc, info.absoluteResourcePath) - .replace(/\\/g, '/'), - }, - resolve: { - // This allows you to set a fallback for where Webpack should look for modules. - // We placed these paths second because we want `node_modules` to "win" - // if there are any conflicts. This matches Node resolution mechanism. - // https://github.com/facebookincubator/create-react-app/issues/253 - modules: ['node_modules', paths.appNodeModules].concat( - // It is guaranteed to exist because we tweak it in `env.js` - process.env.NODE_PATH.split(path.delimiter).filter(Boolean) - ), - // These are the reasonable defaults supported by the Node ecosystem. - // We also include JSX as a common component filename extension to support - // some tools, although we do not recommend using it, see: - // https://github.com/facebookincubator/create-react-app/issues/290 - // `web` extension prefixes have been added for better support - // for React Native Web. - extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'], - alias: { - // @remove-on-eject-begin - // Resolve Babel runtime relative to react-scripts. - // It usually still works on npm 3 without this but it would be - // unfortunate to rely on, as react-scripts could be symlinked, - // and thus babel-runtime might not be resolvable from the source. - 'babel-runtime': path.dirname( - require.resolve('babel-runtime/package.json') - ), - // @remove-on-eject-end - // Support React Native Web - // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ - 'react-native': 'react-native-web', - }, - plugins: [ - // Prevents users from importing files from outside of src/ (or node_modules/). - // This often causes confusion because we only process files within src/ with babel. - // To fix this, we prevent you from importing files out of src/ -- if you'd like to, - // please link the files into your node_modules/ and let module-resolution kick in. - // Make sure your source files are compiled, as they will not be processed in any way. - new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]), - ], - }, - module: { - strictExportPresence: true, - rules: [ - // TODO: Disable require.ensure as it's not a standard language feature. - // We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176. - // { parser: { requireEnsure: false } }, - - // First, run the linter. - // It's important to do this before Babel processes the JS. - { - test: /\.(js|jsx|mjs)$/, - enforce: 'pre', - use: [ - { - options: { - formatter: eslintFormatter, - eslintPath: require.resolve('eslint'), - // @remove-on-eject-begin - // TODO: consider separate config for production, - // e.g. to enable no-console and no-debugger only in production. - baseConfig: { - extends: [require.resolve('eslint-config-react-app')], - }, - ignore: false, - useEslintrc: false, - // @remove-on-eject-end - }, - loader: require.resolve('eslint-loader'), - }, - ], - include: paths.appSrc, - }, - { - // "oneOf" will traverse all following loaders until one will - // match the requirements. When no loader matches it will fall - // back to the "file" loader at the end of the loader list. - oneOf: [ - // "url" loader works just like "file" loader but it also embeds - // assets smaller than specified size as data URLs to avoid requests. - { - test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], - loader: require.resolve('url-loader'), - options: { - limit: 10000, - name: 'static/media/[name].[hash:8].[ext]', - }, - }, - // Process JS with Babel. - { - test: /\.(js|jsx|mjs)$/, - include: paths.appSrc, - loader: require.resolve('babel-loader'), - options: { - // @remove-on-eject-begin - babelrc: false, - presets: [require.resolve('babel-preset-react-app')], - // @remove-on-eject-end - compact: true, - }, - }, - // The notation here is somewhat confusing. - // "postcss" loader applies autoprefixer to our CSS. - // "css" loader resolves paths in CSS and adds assets as dependencies. - // "style" loader normally turns CSS into JS modules injecting