Compare commits

..

No commits in common. "develop" and "v2.0.0" have entirely different histories.

64 changed files with 9116 additions and 10479 deletions

View File

@ -1,18 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.

View File

@ -1,13 +1,13 @@
# Editor configuration, see https://editorconfig.org
root = true root = true
[*] [*]
charset = utf-8 charset = utf-8
indent_size = 2
indent_style = space indent_style = space
indent_size = 2
insert_final_newline = true insert_final_newline = true
max_line_length = 140
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.md] [*.md]
max_line_length = false max_line_length = off
trim_trailing_whitespace = false trim_trailing_whitespace = false

View File

@ -1,8 +0,0 @@
.angular
.pnpm-store
dist
e2e/protractor.conf.js
node_modules
pnpm-lock.yaml
public
src/test.ts

View File

@ -1,134 +0,0 @@
{
"root": true,
"env": {
"browser": true
},
"ignorePatterns": ["projects/**/*"],
"overrides": [
{
"files": ["*.ts"],
"parserOptions": {
"project": ["tsconfig.json", "e2e/tsconfig.json"],
"createDefaultProgram": true
},
"plugins": ["rxjs-angular"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"prettier",
"plugin:rxjs/recommended",
"plugin:@angular-eslint/all",
"plugin:@angular-eslint/recommended--extra",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
],
// Custom rules
// @typescript-eslint
"@typescript-eslint/array-type": "error",
"@typescript-eslint/class-literal-property-style": "error",
"@typescript-eslint/consistent-indexed-object-style": "error",
"@typescript-eslint/consistent-type-assertions": [
"error",
{
"assertionStyle": "as",
"objectLiteralTypeAssertions": "never"
}
],
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/dot-notation": "error",
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "no-public"
}
],
"@typescript-eslint/member-delimiter-style": [
"error",
{
"multiline": {
"delimiter": "none",
"requireLast": true
}
}
],
"@typescript-eslint/method-signature-style": "error",
"@typescript-eslint/no-base-to-string": "error",
"@typescript-eslint/no-confusing-non-null-assertion": "error",
"@typescript-eslint/no-confusing-void-expression": [
"error",
{
"ignoreArrowShorthand": true,
"ignoreVoidOperator": true
}
],
"@typescript-eslint/no-dynamic-delete": "error",
"@typescript-eslint/no-empty-function": [
"error",
{
"allow": ["private-constructors", "protected-constructors"]
}
],
"@typescript-eslint/no-extra-parens": ["error", "functions"],
"@typescript-eslint/no-implicit-any-catch": "error",
"@typescript-eslint/no-invalid-void-type": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
"@typescript-eslint/no-unnecessary-condition": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-arguments": "error",
"@typescript-eslint/no-unnecessary-type-constraint": "error",
"@typescript-eslint/no-unsafe-argument": "error",
"@typescript-eslint/no-unsafe-assignment": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/non-nullable-type-assertion-style": "error",
"@typescript-eslint/prefer-for-of": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-nullish-coalescing": "error",
"@typescript-eslint/prefer-optional-chain": "error",
"@typescript-eslint/prefer-readonly": "error",
"@typescript-eslint/prefer-reduce-type-parameter": "error",
"@typescript-eslint/prefer-return-this-type": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/prefer-ts-expect-error": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/semi": ["error", "never"],
"@typescript-eslint/sort-type-union-intersection-members": "error",
"@typescript-eslint/switch-exhaustiveness-check": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unified-signatures": "error",
// eslint-plugin-rxjs-angular
//"rxjs-angular/prefer-async-pipe": "error",
"rxjs-angular/prefer-takeuntil": "error"
}
},
{
"files": ["*.html"],
"extends": ["plugin:@angular-eslint/template/all"],
"rules": {
// Custom rules
"@angular-eslint/template/i18n": "off"
}
}
]
}

12
.github/FUNDING.yml vendored
View File

@ -1,12 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: NatoBoram # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ["https://paypal.me/NatoBoram/5"] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

142
.gitignore vendored
View File

@ -1,126 +1,46 @@
# Created by https://www.toptal.com/developers/gitignore/api/angular,linux,windows,macos,visualstudiocode # See http://help.github.com/ignore-files/ for more about ignoring files.
# Edit at https://www.toptal.com/developers/gitignore?templates=angular,linux,windows,macos,visualstudiocode
### Angular ###
## Angular ##
# compiled output # compiled output
dist/ /dist
tmp/ /tmp
app/**/*.js /out-tsc
app/**/*.js.map # Only exists if Bazel was run
/bazel-out
# dependencies # dependencies
node_modules/ /node_modules
bower_components/
# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json
# IDEs and editors # IDEs and editors
.idea/ /.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# misc # IDE - VSCode
.sass-cache/
connect.lock/
coverage/
libpeerconnection.log/
npm-debug.log
testem.log
typings/
.angular/
# e2e
e2e/*.js
e2e/*.map
# System Files
.DS_Store/
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### VisualStudioCode ###
.vscode/* .vscode/*
!.vscode/settings.json !.vscode/settings.json
!.vscode/tasks.json !.vscode/tasks.json
!.vscode/launch.json !.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
!.vscode/*.code-snippets .history/*
# Local History for Visual Studio Code # misc
.history/ /.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# Built Visual Studio Code Extensions # System Files
*.vsix .DS_Store
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# Support for Project snippet scope
### Windows ###
# Windows thumbnail cache files
Thumbs.db Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/angular,linux,windows,macos,visualstudiocode

View File

@ -1,25 +1,20 @@
image: node:latest image: node:13
before_script: before_script:
- curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@6 - yarn
- pnpm config set store-dir .pnpm-store
- pnpm i
variables:
# https://stackoverflow.com/a/69746937/5083247
NODE_OPTIONS: --openssl-legacy-provider
cache: cache:
key: key:
files: files:
- pnpm-lock.yaml - package.json
- yarn.lock
paths: paths:
- .pnpm-store - node_modules
build: build:
stage: build stage: build
script: script:
- pnpm run build:prod - yarn run build:prod
artifacts: artifacts:
paths: paths:
- dist/angular - dist/angular
@ -27,13 +22,12 @@ build:
test: test:
stage: test stage: test
script: script:
- pnpx ng lint - yarn run lint
- pnpx prettier --check .
pages: pages:
stage: deploy stage: deploy
script: script:
- pnpm run build:gitlab - yarn run build:gitlab
- mv dist/angular public - mv dist/angular public
- cp public/index.html public/404.html - cp public/index.html public/404.html
artifacts: artifacts:

View File

@ -1,3 +1,3 @@
{ {
"packageManager": "pnpm" "packageManager": "yarn"
} }

View File

@ -1,4 +1,4 @@
{ {
"line_length": false, "line-length": false,
"no-duplicate-heading": false "no-duplicate-heading": false
} }

View File

@ -1,6 +0,0 @@
.angular
.pnpm-store
dist
node_modules
pnpm-lock.yaml
public

View File

@ -1,3 +0,0 @@
arrowParens: avoid
printWidth: 140
semi: false

View File

@ -5,19 +5,16 @@
"recommendations": [ "recommendations": [
"angular.ng-template", "angular.ng-template",
"davidanson.vscode-markdownlint", "davidanson.vscode-markdownlint",
"dbaeumer.vscode-eslint",
"editorconfig.editorconfig", "editorconfig.editorconfig",
"esbenp.prettier-vscode", "hookyqr.beautify",
"gitlab.gitlab-workflow",
"johnpapa.angular2", "johnpapa.angular2",
"ms-vscode.vscode-typescript-next", "ms-vscode.typescript-javascript-grammar",
"visualstudioexptteam.vscodeintellicode" "ms-vscode.vscode-typescript-tslint-plugin",
"msjsdiag.debugger-for-chrome",
"visualstudioexptteam.vscodeintellicode",
], ],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace. // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [ "unwantedRecommendations": [
"eg2.tslint", "eg2.tslint"
"ms-azuretools.vscode-docker",
"ms-edgedevtools.vscode-edge-devtools",
"ms-vscode-remote.remote-wsl"
] ]
} }

4
.vscode/launch.json vendored
View File

@ -37,7 +37,9 @@
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/node_modules/protractor/bin/protractor", "program": "${workspaceFolder}/node_modules/protractor/bin/protractor",
"protocol": "inspector", "protocol": "inspector",
"args": ["${workspaceFolder}/e2e/protractor.conf.js"] "args": [
"${workspaceFolder}/e2e/protractor.conf.js"
]
} }
] ]
} }

25
.vscode/settings.json vendored
View File

@ -1,30 +1,17 @@
{ {
"[css][scss][html][javascript][typescript][json][jsonc][markdown][yaml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll": true, "source.fixAll": true,
"source.fixAll.eslint": true,
"source.organizeImports": true
}, },
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.rulers": [140], "editor.rulers": [
"eslint.options": { 140
"extensions": [".ts", ".html"] ],
},
"eslint.packageManager": "pnpm",
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "html"],
"files.associations": {
".ipfs-npmrc": "json"
},
"html.format.indentHandlebars": true, "html.format.indentHandlebars": true,
"html.format.maxPreserveNewLines": 1, "html.format.maxPreserveNewLines": 1,
"html.format.wrapAttributes": "auto", "html.format.wrapAttributes": "auto",
"html.format.wrapLineLength": 140, "html.format.wrapLineLength": 140,
"npm.packageManager": "pnpm", "npm.packageManager": "yarn",
"tslint.packageManager": "pnpm", "tslint.packageManager": "yarn",
"typescript.preferences.importModuleSpecifier": "relative", "typescript.preferences.importModuleSpecifier": "relative",
"typescript.tsdk": "node_modules\\typescript\\lib", "typescript.updateImportsOnFileMove.enabled": "always",
"typescript.updateImportsOnFileMove.enabled": "always"
} }

7
.vscode/tasks.json vendored
View File

@ -17,7 +17,10 @@
"owner": "typescript", "owner": "typescript",
"source": "ts", "source": "ts",
"applyTo": "closedDocuments", "applyTo": "closedDocuments",
"fileLocation": ["relative", "${cwd}"], "fileLocation": [
"relative",
"${cwd}"
],
"pattern": "$tsc", "pattern": "$tsc",
"background": { "background": {
"activeOnStart": true, "activeOnStart": true,
@ -29,6 +32,6 @@
} }
} }
} }
} },
] ]
} }

View File

@ -18,63 +18,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
### Security ### Security
## [2.2.1]
### Changed
- Updated my own gateway to its HTTPS link
## [2.2.0] - 2022-03-11
### Added
- More information in the `package.json`.
- Added ESLint
- Added Prettier
- Put success reponses at the top of the list
### Changed
- Updated `gateways.json`
- Upgraded to Angular 13
- Targets ESNext
### Removed
- Removed TSLint
## [2.1.1] - 2021-03-20
### Added
- Added some accessibility tags
- Added some VSCode settings
### Changed
- Updated to Angular 11
- Updated gateways
### Fixed
- Corrected the title from "Public IPFS Cacher" to "Public Gateway Cacher".
## [2.1.0] - 2020-07-10
### Added
- Support for subdomain gateways
- Strict mode
- More icons
- IPFS colours
### Changed
- Better screenshot
- Upgraded to Angular 10
- Now uses `--chunker=buzhash`
- Updated `bootstrap` and `ipfs-css`
## [2.0.0] - 2019-12-03 ## [2.0.0] - 2019-12-03
Now based on Angular! Now based on Angular!
@ -83,7 +26,7 @@ Tests were done with `ipfs-npm` : They weren't successful. `ipfs-css` is only mi
### Added ### Added
- GitLab Pages - <https://natoboram.gitlab.io/public-gateway-cacher/> * GitLab Pages - <https://natoboram.gitlab.io/public-gateway-cacher/>
## [1.0.0] - 2019-11-28 ## [1.0.0] - 2019-11-28
@ -91,9 +34,9 @@ This version is a fork of [github.com/ipfs/public-gateway-checker](https://githu
## Types of changes ## Types of changes
- `Added` for new features. * `Added` for new features.
- `Changed` for changes in existing functionality. * `Changed` for changes in existing functionality.
- `Deprecated` for soon-to-be removed features. * `Deprecated` for soon-to-be removed features.
- `Removed` for now removed features. * `Removed` for now removed features.
- `Fixed` for any bug fixes. * `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities. * `Security` in case of vulnerabilities.

View File

@ -1,14 +1,41 @@
# Public Gateway Cacher # Public Gateway Cacher
[![pipeline status](https://gitlab.com/NatoBoram/public-gateway-cacher/badges/master/pipeline.svg)](https://gitlab.com/NatoBoram/public-gateway-cacher/-/commits/master)
[![StackShare](https://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/NatoBoram/public-gateway-cacher)
Cache a specific hash on a bunch of public gateways. Cache a specific hash on a bunch of public gateways.
You can view this website on [GitLab Pages](https://natoboram.gitlab.io/public-gateway-cacher) and [IPFS](https://bafybeievsdzxuvuah5t6vzhig525jecp7wmupnm7olxdkonqmte57zoqf4.ipfs.dweb.link). **Note :** All of these (except gateway.ipfs.io and ipfs.io) are hosted by third-parties and should be treated as such.
![Screenshot](https://bafybeie7txrbzw6ipb62lplnpzsjpz7s4o5q7uufb5rjfelol2cuxeyzye.ipfs.dweb.link/Screenshot_2020-07-09%20Public%20Gateway%20Cacher.png) You can view this website on [IPFS](https://bafybeibjf6z3sxavox6uahfl4vogkuenimlpvn4eghdv6mtsm55rpnalve.cf-ipfs.com).
**NOTE :** All of these (except `ipfs.io` and `dweb.link`) are hosted by third-parties and should be treated as such. Here's a screenshot :
If you'd like to add a new public gateway, please go to [github.com/ipfs/public-gateway-checker](https://github.com/ipfs/public-gateway-checker), submit a pull request then open an issue [here](https://gitlab.com/NatoBoram/public-gateway-cacher/issues/new). ![screenshot](https://ipfs.io/ipfs/QmUeCSd4gHio7MxZuRXCcLFXED9GpfntKcL87gmXvZV3ed)
If you'd like to add a new public gateway, please go to [github.com/ipfs/public-gateway-checker](https://github.com/ipfs/public-gateway-checker), submit a pull request then open an issue here.
## Angular
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.20.
### Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
### Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
### Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
### Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
### Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
### Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@ -1,11 +1,6 @@
{ {
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"cli": {
"packageManager": "pnpm",
"analytics": "10b848ad-8b81-4346-852f-5eff89573a85",
"defaultCollection": "@angular-eslint/schematics"
},
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"public-gateway-cacher": { "public-gateway-cacher": {
@ -13,9 +8,6 @@
"schematics": { "schematics": {
"@schematics/angular:component": { "@schematics/angular:component": {
"style": "scss" "style": "scss"
},
"@schematics/angular:application": {
"strict": true
} }
}, },
"root": "", "root": "",
@ -30,18 +22,20 @@
"main": "src/main.ts", "main": "src/main.ts",
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.png", "src/assets"], "aot": true,
"styles": ["src/styles.scss"], "assets": [
"stylePreprocessorOptions": { "src/favicon.png",
"includePaths": ["node_modules"] "src/assets",
}, {
"scripts": [], "glob": "*",
"vendorChunk": true, "input": "node_modules/ipfs-css",
"extractLicenses": false, "output": "assets/ipfs-css"
"buildOptimizer": false, }
"sourceMap": true, ],
"optimization": false, "styles": [
"namedChunks": true "src/styles.scss"
],
"scripts": []
}, },
"configurations": { "configurations": {
"production": { "production": {
@ -53,7 +47,12 @@
], ],
"optimization": true, "optimization": true,
"outputHashing": "all", "outputHashing": "all",
"sourceMap": true,
"extractCss": true,
"namedChunks": true,
"aot": true,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": true,
"buildOptimizer": true, "buildOptimizer": true,
"budgets": [ "budgets": [
{ {
@ -77,7 +76,12 @@
], ],
"optimization": true, "optimization": true,
"outputHashing": "all", "outputHashing": "all",
"sourceMap": true,
"extractCss": true,
"namedChunks": true,
"aot": true,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": true,
"buildOptimizer": true, "buildOptimizer": true,
"budgets": [ "budgets": [
{ {
@ -101,7 +105,12 @@
], ],
"optimization": true, "optimization": true,
"outputHashing": "all", "outputHashing": "all",
"sourceMap": true,
"extractCss": true,
"namedChunks": true,
"aot": true,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": true,
"buildOptimizer": true, "buildOptimizer": true,
"budgets": [ "budgets": [
{ {
@ -116,8 +125,7 @@
} }
] ]
} }
}, }
"defaultConfiguration": ""
}, },
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
@ -143,14 +151,34 @@
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js", "karmaConfig": "karma.conf.js",
"assets": ["src/favicon.png", "src/assets"], "assets": [
"styles": ["src/styles.scss"], "src/favicon.png",
"stylePreprocessorOptions": { "src/assets",
"includePaths": ["node_modules"] {
}, "glob": "*",
"input": "node_modules/ipfs-css",
"output": "assets/ipfs-css"
}
],
"styles": [
"src/styles.scss"
],
"scripts": [] "scripts": []
} }
}, },
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": { "e2e": {
"builder": "@angular-devkit/build-angular:protractor", "builder": "@angular-devkit/build-angular:protractor",
"options": { "options": {
@ -162,15 +190,12 @@
"devServerTarget": "public-gateway-cacher:serve:production" "devServerTarget": "public-gateway-cacher:serve:production"
} }
} }
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
}
} }
} }
} }
}, },
"defaultProject": "public-gateway-cacher" "defaultProject": "public-gateway-cacher",
"cli": {
"packageManager": "yarn"
}
} }

12
browserslist Normal file
View File

@ -0,0 +1,12 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

View File

@ -2,35 +2,31 @@
// Protractor configuration file, see link for more information // Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts // https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter, StacktraceOption } = require("jasmine-spec-reporter") const { SpecReporter } = require('jasmine-spec-reporter');
/** /**
* @type { import("protractor").Config } * @type { import("protractor").Config }
*/ */
exports.config = { exports.config = {
allScriptsTimeout: 11000, allScriptsTimeout: 11000,
specs: ["./src/**/*.e2e-spec.ts"], specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: { capabilities: {
browserName: "chrome", browserName: 'chrome'
}, },
directConnect: true, directConnect: true,
baseUrl: "http://localhost:4200/", baseUrl: 'http://localhost:4200/',
framework: "jasmine", framework: 'jasmine',
jasmineNodeOpts: { jasmineNodeOpts: {
showColors: true, showColors: true,
defaultTimeoutInterval: 30000, defaultTimeoutInterval: 30000,
print: function () {}, print: function() {}
}, },
onPrepare() { onPrepare() {
require("ts-node").register({ require('ts-node').register({
project: require("path").join(__dirname, "./tsconfig.json"), project: require('path').join(__dirname, './tsconfig.json')
}) });
jasmine.getEnv().addReporter( jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
new SpecReporter({ }
spec: { };
displayStacktrace: StacktraceOption.PRETTY,
},
})
)
},
}

View File

@ -1,25 +1,23 @@
import { browser, logging } from "protractor" import { browser, logging } from 'protractor';
import { AppPage } from "./app.po" import { AppPage } from './app.po';
describe("workspace-project App", (): void => { describe('workspace-project App', () => {
let page: AppPage let page: AppPage;
beforeEach((): void => { beforeEach(() => {
page = new AppPage() page = new AppPage();
}) });
it("should display welcome message", (): void => { it('should display welcome message', () => {
void page.navigateTo() page.navigateTo();
void expect(page.getTitleText()).toEqual("public-gateway-cacher app is running!") expect(page.getTitleText()).toEqual('public-gateway-cacher app is running!');
}) });
afterEach(async (): Promise<void> => { afterEach(async () => {
// Assert that there are no errors emitted from the browser // Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER) const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const expected: Partial<logging.Entry> = { expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE, level: logging.Level.SEVERE,
} } as logging.Entry));
});
void expect(logs).not.toContain(jasmine.objectContaining(expected)) });
})
})

View File

@ -1,11 +1,11 @@
import { browser, by, element } from "protractor" import { browser, by, element } from 'protractor';
export class AppPage { export class AppPage {
async navigateTo(): Promise<unknown> { navigateTo() {
return browser.get(browser.baseUrl) as Promise<unknown> return browser.get(browser.baseUrl) as Promise<any>;
} }
async getTitleText(): Promise<string> { getTitleText() {
return element(by.css("pgc-root .content span")).getText() as Promise<string> return element(by.css('app-root .content span')).getText() as Promise<string>;
} }
} }

View File

@ -1,10 +1,13 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"extends": "../tsconfig.json", "extends": "../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "../out-tsc/e2e", "outDir": "../out-tsc/e2e",
"module": "commonjs", "module": "commonjs",
"target": "ESNext", "target": "es5",
"types": ["jasmine", "jasminewd2", "node"] "types": [
"jasmine",
"jasminewd2",
"node"
]
} }
} }

View File

@ -3,30 +3,30 @@
module.exports = function (config) { module.exports = function (config) {
config.set({ config.set({
basePath: "", basePath: '',
frameworks: ["jasmine", "@angular-devkit/build-angular"], frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [ plugins: [
require("karma-jasmine"), require('karma-jasmine'),
require("karma-chrome-launcher"), require('karma-chrome-launcher'),
require("karma-jasmine-html-reporter"), require('karma-jasmine-html-reporter'),
require("karma-coverage-istanbul-reporter"), require('karma-coverage-istanbul-reporter'),
require("@angular-devkit/build-angular/plugins/karma"), require('@angular-devkit/build-angular/plugins/karma')
], ],
client: { client: {
clearContext: false, // leave Jasmine Spec Runner output visible in browser clearContext: false // leave Jasmine Spec Runner output visible in browser
}, },
coverageIstanbulReporter: { coverageIstanbulReporter: {
dir: require("path").join(__dirname, "./coverage/public-gateway-cacher"), dir: require('path').join(__dirname, './coverage/public-gateway-cacher'),
reports: ["html", "lcovonly", "text-summary"], reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true, fixWebpackSourcePaths: true
}, },
reporters: ["progress", "kjhtml"], reporters: ['progress', 'kjhtml'],
port: 9876, port: 9876,
colors: true, colors: true,
logLevel: config.LOG_INFO, logLevel: config.LOG_INFO,
autoWatch: true, autoWatch: true,
browsers: ["Chrome"], browsers: ['Chrome'],
singleRun: false, singleRun: false,
restartOnFileChange: true, restartOnFileChange: true
}) });
} };

View File

@ -1,28 +1,6 @@
{ {
"name": "public-gateway-cacher", "name": "public-gateway-cacher",
"version": "2.2.1", "version": "2.0.0",
"description": "Cache a specific hash on a bunch of public gateways.",
"keywords": [
"IPFS"
],
"homepage": "https://natoboram.gitlab.io/public-gateway-cacher",
"bugs": {
"url": "https://gitlab.com/NatoBoram/public-gateway-cacher/-/issues",
"email": "contact-project+natoboram-public-gateway-cacher-11685619-issue-@incoming.gitlab.com"
},
"license": "GPL-3.0-or-later",
"author": {
"name": "Nato Boram",
"url": "https://gitlab.com/NatoBoram"
},
"funding": [
{
"type": "patreon",
"url": "https://www.patreon.com/NatoBoram"
},
"https://paypal.me/NatoBoram/5"
],
"repository": "gitlab:NatoBoram/public-gateway-cacher",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve --ssl", "start": "ng serve --ssl",
@ -31,61 +9,54 @@
"build:gitlab": "ng build --configuration=gitlab --base-href /public-gateway-cacher/", "build:gitlab": "ng build --configuration=gitlab --base-href /public-gateway-cacher/",
"build:ipfs": "ng build --configuration=ipfs", "build:ipfs": "ng build --configuration=ipfs",
"test": "ng test", "test": "ng test",
"lint": "ng lint --fix", "lint": "ng lint",
"eslint": "eslint --fix .",
"prettier": "prettier --write .",
"e2e": "ng e2e", "e2e": "ng e2e",
"publish:ipfs": "pnpm run build:ipfs && ipfs add --recursive --chunker=buzhash --cid-version=1 dist/angular", "yarn": "ipfs-yarn",
"postinstall": "ngcc" "publish:ipfs": "yarn run build:ipfs; ipfs add --recursive --chunker=rabin --cid-version=1 dist/angular"
}, },
"private": false,
"dependencies": { "dependencies": {
"@angular/animations": "~13.3.9", "@angular/animations": "~8.2.14",
"@angular/cdk": "~13.3.7", "@angular/cdk": "~8.2.3",
"@angular/common": "~13.3.9", "@angular/common": "~8.2.14",
"@angular/compiler": "~13.3.9", "@angular/compiler": "~8.2.14",
"@angular/core": "~13.3.9", "@angular/core": "~8.2.14",
"@angular/flex-layout": "^13.0.0-beta.38", "@angular/flex-layout": "^8.0.0-beta.27",
"@angular/forms": "~13.3.9", "@angular/forms": "~8.2.14",
"@angular/material": "^13.3.7", "@angular/material": "^8.2.3",
"@angular/platform-browser": "~13.3.9", "@angular/platform-browser": "~8.2.14",
"@angular/platform-browser-dynamic": "~13.3.9", "@angular/platform-browser-dynamic": "~8.2.14",
"@angular/router": "~13.3.9", "@angular/router": "~8.2.14",
"bootstrap": "^5.1.3", "bootstrap": "^4.4.1",
"ipfs-css": "^1.3.0", "hammerjs": "^2.0.8",
"rxjs": "~7.5.5", "ipfs-css": "^0.13.1",
"tslib": "^2.0.0", "rxjs": "~6.5.3",
"zone.js": "~0.11.4" "tslib": "^1.10.0",
"zone.js": "~0.9.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~13.3.6", "@angular-devkit/build-angular": "~0.803.20",
"@angular-eslint/builder": "13.2.1", "@angular/cli": "~8.3.20",
"@angular-eslint/eslint-plugin": "13.2.1", "@angular/compiler-cli": "~8.2.14",
"@angular-eslint/eslint-plugin-template": "13.2.1", "@angular/language-service": "~8.2.14",
"@angular-eslint/schematics": "13.2.1", "@types/jasmine": "~3.3.8",
"@angular-eslint/template-parser": "13.2.1",
"@angular/cli": "~13.3.6",
"@angular/compiler-cli": "~13.3.9",
"@angular/language-service": "~13.3.9",
"@types/jasmine": "~3.10.3",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "^17.0.21", "@types/node": "~8.9.4",
"@typescript-eslint/eslint-plugin": "5.14.0", "codelyzer": "^5.0.0",
"@typescript-eslint/parser": "5.14.0", "jasmine-core": "~3.4.0",
"eslint": "^8.2.0", "jasmine-spec-reporter": "~4.2.1",
"eslint-config-prettier": "^8.5.0", "karma": "~4.1.0",
"eslint-plugin-rxjs": "^5.0.2", "karma-chrome-launcher": "~2.2.0",
"eslint-plugin-rxjs-angular": "^2.0.0", "karma-coverage-istanbul-reporter": "~2.0.1",
"jasmine-core": "~4.0.1", "karma-jasmine": "~2.0.1",
"jasmine-spec-reporter": "~7.0.0", "karma-jasmine-html-reporter": "^1.4.0",
"karma": "~6.3.17", "protractor": "~5.4.0",
"karma-chrome-launcher": "~3.1.0", "rxjs-tslint-rules": "^4.26.3",
"karma-coverage-istanbul-reporter": "~3.0.2", "ts-node": "~7.0.0",
"karma-jasmine": "~4.0.0", "tslint": "~5.15.0",
"karma-jasmine-html-reporter": "^1.5.0", "tslint-consistent-codestyle": "^1.16.0",
"prettier": "^2.5.1", "tslint-origin-ordered-imports-rule": "^1.2.2",
"protractor": "~7.0.0", "tslint-rxjs-subject-restrictions-rule": "^1.0.4",
"ts-node": "~10.7.0", "typescript": "~3.5.3"
"typescript": "~4.5.5" }
},
"private": true
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,14 @@
import { NgModule } from "@angular/core" import { NgModule } from '@angular/core';
import type { Routes } from "@angular/router" import { RouterModule, Routes } from '@angular/router';
import { RouterModule } from "@angular/router" import { environment } from '../environments/environment';
import { environment } from "../environments/environment"
const routes: Routes = [ const routes: Routes = [{
{ path: '',
path: "", loadChildren: () => import('./pages/pages.module').then(m => m.PagesModule),
loadChildren: async () => import("./pages/pages.module").then(m => m.PagesModule), }];
},
]
@NgModule({ @NgModule({
imports: [RouterModule.forRoot(routes, { useHash: environment.useHash, relativeLinkResolution: "legacy" })], imports: [RouterModule.forRoot(routes, { useHash: environment.useHash })],
exports: [RouterModule], exports: [RouterModule]
}) })
export class AppRoutingModule {} export class AppRoutingModule { }

View File

@ -1,9 +1 @@
<mat-toolbar color="primary" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="1em">
<h1>Public Gateway Cacher</h1>
<!-- Theme Switcher -->
<button mat-icon-button="">
<mat-icon (click)="themeService.switchTheme()">{{ themeService.icon }}</mat-icon>
</button>
</mat-toolbar>
<router-outlet></router-outlet> <router-outlet></router-outlet>

View File

@ -1,41 +1,35 @@
import { TestBed, waitForAsync } from "@angular/core/testing" import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from "@angular/router/testing" import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from "./app.component" import { AppComponent } from './app.component';
describe("AppComponent", (): void => { describe('AppComponent', () => {
beforeEach(waitForAsync((): void => { beforeEach(async(() => {
void TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [RouterTestingModule], imports: [
declarations: [AppComponent], RouterTestingModule
}).compileComponents() ],
})) declarations: [
AppComponent
],
}).compileComponents();
}));
it("should create the app", (): void => { it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent) const fixture = TestBed.createComponent(AppComponent);
if (!(fixture.debugElement.componentInstance instanceof AppComponent)) throw new Error("Expected AppComponent") const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
const app: AppComponent = fixture.debugElement.componentInstance it(`should have as title 'public-gateway-cacher'`, () => {
void expect(app).toBeTruthy() const fixture = TestBed.createComponent(AppComponent);
}) const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('public-gateway-cacher');
});
it(`should have a themeService`, (): void => { it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent) const fixture = TestBed.createComponent(AppComponent);
if (!(fixture.debugElement.componentInstance instanceof AppComponent)) throw new Error("Expected AppComponent") fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
const app: AppComponent = fixture.debugElement.componentInstance expect(compiled.querySelector('.content span').textContent).toContain('public-gateway-cacher app is running!');
void expect(app.themeService).toBeTruthy() });
}) });
it("should render title", (): void => {
const fixture = TestBed.createComponent(AppComponent)
fixture.detectChanges()
if (!isHTMLElement(fixture.debugElement.nativeElement)) throw new Error("Expected HTMLElement")
const compiled: HTMLElement = fixture.debugElement.nativeElement
void expect(compiled.querySelector("h1")?.textContent).toContain("Public Gateway Cacher")
})
})
function isHTMLElement(element: unknown): element is HTMLElement {
return Object.getPrototypeOf(element) instanceof HTMLElement
}

View File

@ -1,12 +1,10 @@
import { ChangeDetectionStrategy, Component, Inject } from "@angular/core" import { Component } from '@angular/core';
import { ThemeService } from "./services/theme.service"
@Component({ @Component({
selector: "app-root", selector: 'app-root',
templateUrl: "./app.component.html", templateUrl: './app.component.html',
styleUrls: ["./app.component.scss"], styleUrls: ['./app.component.scss']
changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AppComponent { export class AppComponent {
constructor(@Inject(ThemeService) readonly themeService: ThemeService) {} title = 'public-gateway-cacher';
} }

View File

@ -1,29 +1,23 @@
import { CommonModule } from "@angular/common" import { CommonModule } from '@angular/common';
import { HttpClientModule } from "@angular/common/http" import { HttpClientModule } from '@angular/common/http';
import { NgModule } from "@angular/core" import { NgModule } from '@angular/core';
import { FlexLayoutModule } from "@angular/flex-layout" import { BrowserModule } from '@angular/platform-browser';
import { MatButtonModule } from "@angular/material/button" import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatIconModule } from "@angular/material/icon" import { AppRoutingModule } from './app-routing.module';
import { MatToolbarModule } from "@angular/material/toolbar" import { AppComponent } from './app.component';
import { BrowserModule } from "@angular/platform-browser"
import { BrowserAnimationsModule } from "@angular/platform-browser/animations"
import { AppRoutingModule } from "./app-routing.module"
import { AppComponent } from "./app.component"
@NgModule({ @NgModule({
declarations: [AppComponent], declarations: [
AppComponent
],
imports: [ imports: [
AppRoutingModule,
BrowserAnimationsModule,
BrowserModule,
CommonModule, CommonModule,
FlexLayoutModule, BrowserModule,
BrowserAnimationsModule,
HttpClientModule, HttpClientModule,
MatButtonModule, AppRoutingModule,
MatIconModule,
MatToolbarModule,
], ],
providers: [], providers: [],
bootstrap: [AppComponent], bootstrap: [AppComponent]
}) })
export class AppModule {} export class AppModule { }

View File

@ -1,4 +0,0 @@
export enum Protocol {
IPFS = "ipfs",
IPNS = "ipns",
}

View File

@ -1,4 +0,0 @@
export enum Theme {
Light = "theme-light",
Dark = "theme-dark",
}

View File

@ -1,5 +1,5 @@
export interface Environment { export interface Environment {
production: boolean production: boolean;
base_href?: string base_href?: string;
useHash: boolean useHash: boolean;
} }

View File

@ -1,9 +0,0 @@
{
"name": "public-gateway-cacher",
"private": true,
"description_1": "This is a special package.json file that is not used by package managers.",
"description_2": "It is used to tell the tools and bundlers whether the code under this directory is free of code with non-local side-effect. Any code that does have non-local side-effects can't be well optimized (tree-shaken) and will result in unnecessary increased payload size.",
"description_3": "It should be safe to set this option to 'false' for new applications, but existing code bases could be broken when built with the production config if the application code does contain non-local side-effects that the application depends on.",
"description_4": "To learn more about this file see: https://angular.io/config/app-package-json.",
"sideEffects": false
}

View File

@ -1,17 +1,14 @@
import { NgModule } from "@angular/core" import { NgModule } from '@angular/core';
import type { Routes } from "@angular/router" import { RouterModule, Routes } from '@angular/router';
import { RouterModule } from "@angular/router" import { PagesComponent } from './pages.component';
import { PagesComponent } from "./pages.component"
const routes: Routes = [ const routes: Routes = [{
{ path: '',
path: "",
component: PagesComponent, component: PagesComponent,
}, }];
]
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule], exports: [RouterModule]
}) })
export class PagesRoutingModule {} export class PagesRoutingModule { }

View File

@ -1,82 +1,84 @@
<div class="container" fxLayout="column" fxLayoutAlign="space-evenly center" fxLayoutGap="1em"> <div fxLayout="column" fxLayoutAlign="space-evenly center" fxLayoutGap="1em" class="container">
<h1>Public IPFS Cacher</h1>
<!-- IPFS --> <!-- IPFS -->
<form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em"> <form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em">
<!-- Hash --> <!-- Hash -->
<mat-form-field [color]="inputColour"> <mat-form-field>
<mat-label>IPFS</mat-label> <mat-label>IPFS</mat-label>
<input name="ipfs" [(ngModel)]="ipfs" matInput /> <input matInput [(ngModel)]="ipfs" name="ipfs">
</mat-form-field> </mat-form-field>
<!-- Cache --> <!-- Cache -->
<button (click)="cacheIPFS()" type="button" mat-flat-button color="primary">Cache</button> <button mat-flat-button color="primary" type="button" (click)="cacheIPFS()">Cache</button>
</form> </form>
<!-- IPNS --> <!-- IPNS -->
<form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em"> <form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em">
<!-- Hash --> <!-- Hash -->
<mat-form-field [color]="inputColour"> <mat-form-field>
<mat-label>IPNS</mat-label> <mat-label>IPNS</mat-label>
<input name="ipns" [(ngModel)]="ipns" matInput /> <input matInput [(ngModel)]="ipns" name="ipns">
</mat-form-field> </mat-form-field>
<!-- Cache --> <!-- Cache -->
<button (click)="cacheIPNS()" type="button" mat-flat-button color="primary">Cache</button> <button mat-flat-button color="primary" type="button" (click)="cacheIPNS()">Cache</button>
</form> </form>
<mat-progress-bar <mat-progress-bar *ngIf="subscriptions.length" mode="determinate" [value]="dataSource.data.length / gateways.length * 100">
[value]="(dataSource.data.length / gateways.length) * 100"
*ngIf="subscriptions.length"
mode="determinate"
color="primary"
>
</mat-progress-bar> </mat-progress-bar>
<table class="mat-elevation-z8" [dataSource]="dataSource" mat-table aria-label="List of IPFS gateways and their statuses."> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- Result Column --> <!-- Result Column -->
<ng-container matColumnDef="icon"> <ng-container matColumnDef="error">
<th mat-header-cell *matHeaderCellDef scope="col">Status</th> <th mat-header-cell *matHeaderCellDef> Status </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span [matTooltip]="element.message"> {{ element.icon }} </span> <div [ngSwitch]="element.error">
<div *ngSwitchCase="null"></div>
<div *ngSwitchDefault [matTooltip]="element.error.statusText"></div>
</div>
</td> </td>
</ng-container> </ng-container>
<!-- Gateway Column --> <!-- Gateway Column -->
<ng-container matColumnDef="gateway"> <ng-container matColumnDef="gateway">
<th mat-header-cell *matHeaderCellDef scope="col">Gateway</th> <th mat-header-cell *matHeaderCellDef> Gateway </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<div [ngSwitch]="element.ok"> <div [ngSwitch]="element.error">
<div *ngSwitchCase="true"> <div *ngSwitchCase="null">
<strong> <strong><a href="{{ element.gateway }}#x-ipfs-companion-no-redirect" class="aqua"> {{ element.gateway }} </a></strong>
<a class="aqua" href="{{ element.gateway }}#x-ipfs-companion-no-redirect" target="_blank">
{{ element.gateway }}
</a>
</strong>
</div> </div>
<div *ngSwitchCase="false"> <div *ngSwitchDefault>
<a class="aqua-muted" href="{{ element.gateway }}#x-ipfs-companion-no-redirect" target="_blank"> <a href="{{ element.gateway }}#x-ipfs-companion-no-redirect" class="aqua-muted"> {{ element.gateway }} </a>
{{ element.gateway }}
</a>
</div> </div>
</div> </div>
</td> </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table> </table>
<!-- About --> <!-- About -->
<div fxLayout="column" fxLayoutAlign="space-evenly start" fxLayoutGap="1em"> <div fxLayout="column" fxLayoutAlign="space-evenly start" fxLayoutGap="1em">
<h3>About</h3> <h3>About</h3>
<p> <p>
This allows you to cache a specific IPFS hash to a bunch of public gateways. It's inspired from This allows you to cache a specific IPFS hash to a bunch of public gateways.
<a class="link" href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>. The source code is It's inspired from <a href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>.
available at <a class="link" href="https://gitlab.com/NatoBoram/public-gateway-cacher">gitlab.com/NatoBoram/public-gateway-cacher</a>. The source code is available at <a
href="https://gitlab.com/NatoBoram/public-gateway-cacher">gitlab.com/NatoBoram/public-gateway-cacher</a>.
</p> </p>
<p> <p>
If you'd like to add a new public gateway, please go to If you'd like to add a new public gateway,
<a class="link" href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>, submit a pull please go to <a href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>,
request then open an issue <a class="link" href="https://gitlab.com/NatoBoram/public-gateway-cacher/issues/new">here</a>. submit a pull request then open an issue <a href="https://gitlab.com/NatoBoram/public-gateway-cacher/issues/new">here</a>.
</p> </p>
</div> </div>
</div> </div>

View File

@ -15,7 +15,7 @@
padding: 1em; padding: 1em;
} }
.mat-column-icon { .mat-column-error {
text-align: center; text-align: center;
width: 5em; width: 5em;
max-width: 100%; max-width: 100%;

View File

@ -1,26 +1,24 @@
import { HttpClientTestingModule } from "@angular/common/http/testing" import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import type { ComponentFixture } from "@angular/core/testing" import { PagesComponent } from './pages.component';
import { TestBed, waitForAsync } from "@angular/core/testing"
import { PagesComponent } from "./pages.component"
describe("PagesComponent", (): void => { describe('PagesComponent', () => {
let component: PagesComponent let component: PagesComponent;
let fixture: ComponentFixture<PagesComponent> let fixture: ComponentFixture<PagesComponent>;
beforeEach(waitForAsync((): void => { beforeEach(async(() => {
void TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [HttpClientTestingModule], declarations: [PagesComponent]
declarations: [PagesComponent],
}).compileComponents()
}))
beforeEach((): void => {
fixture = TestBed.createComponent(PagesComponent)
component = fixture.componentInstance
fixture.detectChanges()
}) })
.compileComponents();
}));
it("should create", (): void => { beforeEach(() => {
void expect(component).toBeTruthy() fixture = TestBed.createComponent(PagesComponent);
}) component = fixture.componentInstance;
}) fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,151 +1,75 @@
import { HttpErrorResponse } from "@angular/common/http" import { HttpErrorResponse } from '@angular/common/http';
import type { OnDestroy, OnInit } from "@angular/core" import { Component, OnInit, ViewChild } from '@angular/core';
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, ViewChild } from "@angular/core" import { MatTable, MatTableDataSource } from '@angular/material/table';
import type { ThemePalette } from "@angular/material/core" import { Subscription } from 'rxjs';
import { MatTable, MatTableDataSource } from "@angular/material/table" import { GatewayService } from '../services/gateway.service';
import type { Subscription } from "rxjs"
import { takeUntil } from "rxjs/operators"
import { environment } from "../../environments/environment"
import { Protocol } from "../enums/protocol.enum"
import { Theme } from "../enums/theme.enum"
import { GatewayService } from "../services/gateway.service"
import { ThemeService } from "../services/theme.service"
@Component({ @Component({
selector: "app-pages", selector: 'app-pages',
templateUrl: "./pages.component.html", templateUrl: './pages.component.html',
styleUrls: ["./pages.component.scss"], styleUrls: ['./pages.component.scss']
changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class PagesComponent implements OnInit, OnDestroy { export class PagesComponent implements OnInit {
@ViewChild(MatTable) matTable!: MatTable<Result>
gateways!: string[] gateways: string[];
inputColour: ThemePalette = "primary" ipfs: string;
ipfs = "" ipns: string;
ipns = "" dataSource: MatTableDataSource<Result>;
displayedColumns = [
'error',
'gateway',
];
subscriptions: Subscription[] = [];
readonly dataSource = new MatTableDataSource<Result>([]) @ViewChild(MatTable, { static: false }) matTable: MatTable<Result>;
readonly displayedColumns = ["icon", "gateway"]
readonly subscriptions: Subscription[] = []
private readonly destroy$ = new EventEmitter<void>()
constructor( constructor(
@Inject(GatewayService) private readonly gatewayService: GatewayService, private readonly gatewayService: GatewayService
@Inject(ThemeService) private readonly themeService: ThemeService ) { }
) {}
ngOnInit(): void { ngOnInit(): void {
this.gatewayService this.dataSource = new MatTableDataSource([]);
.list() this.gatewayService.list().subscribe(gateways => this.gateways = gateways);
.pipe(takeUntil(this.destroy$))
.subscribe((gateways): void => {
this.gateways = gateways
})
// Theme
this.setColours(this.themeService.current)
this.themeService.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((theme): void => {
this.setColours(theme)
})
}
ngOnDestroy(): void {
this.destroy$.next()
this.destroy$.complete()
} }
cacheIPFS(): void { cacheIPFS(): void {
this.ipfs = this.ipfs.trim() this.cache('ipfs', this.ipfs);
this.cache(Protocol.IPFS, this.ipfs)
} }
cacheIPNS(): void { cacheIPNS(): void {
this.ipns = this.ipns.trim() this.cache('ipns', this.ipns);
this.cache(Protocol.IPNS, this.ipns)
} }
cache(protocol: Protocol, hashpath: string): void { cache(type: string, hash: string): void {
// Clear subscriptions
while (this.subscriptions.length) { while (this.subscriptions.length) {
const sub = this.subscriptions.pop() const sub = this.subscriptions.pop();
if (sub && !sub.closed) { if (!sub.closed) {
sub.unsubscribe() sub.unsubscribe();
} }
} }
// Clear table this.dataSource.data = [];
this.dataSource.data = [] this.matTable.renderRows();
this.matTable.renderRows() console.clear();
console.clear()
this.gateways.forEach((gateway): void => { this.gateways.forEach(gateway => {
this.subscriptions.push( this.subscriptions.push(
this.gatewayService this.gatewayService.get(gateway, type, hash).subscribe(_ => {
.get(gateway, protocol, hashpath) this.dataSource.data.push({ gateway: `${gateway.replace(':type', type).replace(':hash', hash)}`, error: null });
.pipe(takeUntil(this.destroy$)) this.matTable.renderRows();
.subscribe( }, (error: HttpErrorResponse) => {
(resp): void => { this.dataSource.data.push({ gateway: `${gateway.replace(':type', type).replace(':hash', hash)}`, error });
this.dataSource.data.unshift({ this.matTable.renderRows();
gateway: this.gatewayService.url(gateway, protocol, hashpath),
message: resp.statusText,
icon: this.getIcon(resp.status),
ok: resp.ok,
}) })
this.matTable.renderRows() );
}, });
(error: unknown): void => {
if (!(error instanceof HttpErrorResponse)) return
this.dataSource.data.push({
gateway: this.gatewayService.url(gateway, protocol, hashpath),
message: error.statusText,
icon: this.getIcon(error.status),
ok: error.ok,
})
this.matTable.renderRows()
}
)
)
})
} }
private setColours(theme: Theme): void {
switch (theme) {
case Theme.Light:
this.inputColour = "primary"
break
case Theme.Dark:
this.inputColour = "accent"
break
default:
break
}
}
private getIcon(status: number): string {
if (status >= 200 && status < 300) {
return "✅"
}
switch (status) {
case 0:
return "❌"
case 403:
return "⛔"
case 404:
return "❓"
case 500:
return "❗"
default:
return environment.production ? "❌" : "❔"
}
}
} }
interface Result { interface Result {
gateway: string gateway: string;
message: string error: HttpErrorResponse;
icon: string
ok: boolean
} }

View File

@ -1,15 +1,15 @@
import { CommonModule } from "@angular/common" import { CommonModule } from '@angular/common';
import { NgModule } from "@angular/core" import { NgModule } from '@angular/core';
import { FlexLayoutModule } from "@angular/flex-layout" import { FlexLayoutModule } from '@angular/flex-layout';
import { FormsModule } from "@angular/forms" import { FormsModule } from '@angular/forms';
import { MatButtonModule } from "@angular/material/button" import { MatButtonModule } from '@angular/material/button';
import { MatInputModule } from "@angular/material/input" import { MatInputModule } from '@angular/material/input';
import { MatProgressBarModule } from "@angular/material/progress-bar" import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSortModule } from "@angular/material/sort" import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from "@angular/material/table" import { MatTableModule } from '@angular/material/table';
import { MatTooltipModule } from "@angular/material/tooltip" import { MatTooltipModule } from '@angular/material/tooltip';
import { PagesRoutingModule } from "./pages-routing.module" import { PagesRoutingModule } from './pages-routing.module';
import { PagesComponent } from "./pages.component" import { PagesComponent } from './pages.component';
@NgModule({ @NgModule({
declarations: [PagesComponent], declarations: [PagesComponent],
@ -24,6 +24,6 @@ import { PagesComponent } from "./pages.component"
MatTableModule, MatTableModule,
MatTooltipModule, MatTooltipModule,
PagesRoutingModule, PagesRoutingModule,
], ]
}) })
export class PagesModule {} export class PagesModule { }

View File

@ -1,18 +1,12 @@
import { HttpClientTestingModule } from "@angular/common/http/testing" import { TestBed } from '@angular/core/testing';
import type { TestBedStatic } from "@angular/core/testing"
import { TestBed } from "@angular/core/testing"
import { GatewayService } from "./gateway.service"
describe("GatewayService", (): void => { import { GatewayService } from './gateway.service';
beforeEach(
(): TestBedStatic =>
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
})
)
it("should be created", (): void => { describe('GatewayService', () => {
const service: GatewayService = TestBed.inject(GatewayService) beforeEach(() => TestBed.configureTestingModule({}));
void expect(service).toBeTruthy()
}) it('should be created', () => {
}) const service: GatewayService = TestBed.get(GatewayService);
expect(service).toBeTruthy();
});
});

View File

@ -1,34 +1,29 @@
import type { HttpResponse } from "@angular/common/http" import { HttpClient } from '@angular/common/http';
import { HttpClient } from "@angular/common/http" import { Injectable } from '@angular/core';
import { Inject, Injectable } from "@angular/core" import { Observable } from 'rxjs';
import type { Observable } from "rxjs" import { environment } from '../../environments/environment';
import { environment } from "../../environments/environment"
import type { Protocol } from "../enums/protocol.enum"
@Injectable({ @Injectable({
providedIn: "root", providedIn: 'root'
}) })
export class GatewayService { export class GatewayService {
constructor(@Inject(HttpClient) private readonly http: HttpClient) {}
constructor(
private readonly http: HttpClient
) { }
list(): Observable<string[]> { list(): Observable<string[]> {
return this.http.get<string[]>( return this.http.get<string[]>(
environment.base_href && environment.base_href !== "/" environment.base_href && environment.base_href !== '/'
? `${environment.base_href}/assets/json/gateways.json` ? `${environment.base_href}/assets/json/gateways.json`
: `${document.querySelector("base")?.href ?? ""}assets/json/gateways.json` : `${document.querySelector('base').href}/assets/json/gateways.json`
) );
} }
get(gateway: string, protocol: Protocol, hashpath: string): Observable<HttpResponse<string>> { get(gateway: string, type: string, hash: string): Observable<Blob> {
return this.http.get(`${this.url(gateway, protocol, hashpath)}#x-ipfs-companion-no-redirect`, { return this.http.get<Blob>(`${gateway.replace(':type', type).replace(':hash', hash)}#x-ipfs-companion-no-redirect`, {
observe: "response", responseType: 'blob' as 'json'
responseType: "text", });
})
} }
url(gateway: string, protocol: Protocol, hashpath: string): string {
const splits: string[] = hashpath.split("/")
const url: string = gateway.replaceAll(":type", protocol).replaceAll(":hash", splits.shift() ?? "")
return splits.length ? [url, splits.join("/")].join("/") : url
}
} }

View File

@ -1,15 +0,0 @@
import { TestBed } from "@angular/core/testing"
import { ThemeService } from "./theme.service"
describe("ThemeService", (): void => {
let service: ThemeService
beforeEach((): void => {
TestBed.configureTestingModule({})
service = TestBed.inject(ThemeService)
})
it("should be created", (): void => {
void expect(service).toBeTruthy()
})
})

View File

@ -1,51 +0,0 @@
import { Injectable } from "@angular/core"
import type { Observable } from "rxjs"
import { Subject } from "rxjs"
import { Theme } from "../enums/theme.enum"
function enumGuard<T>(enumeration: T): (token: unknown) => token is T[keyof T] {
return (token: unknown): token is T[keyof T] => Object.values(enumeration).includes(token)
}
@Injectable({
providedIn: "root",
})
export class ThemeService {
current = Theme.Light
icon = "brightness_low"
readonly valueChanges: Observable<Theme>
private readonly subject$ = new Subject<Theme>()
constructor() {
const stored = localStorage.getItem("theme")
if (enumGuard(Theme)(stored)) {
this.setTheme(stored)
}
this.valueChanges = this.subject$.asObservable()
}
switchTheme(): void {
this.setTheme(this.current === Theme.Light ? Theme.Dark : Theme.Light)
}
setTheme(theme: Theme): void {
document.querySelector("body")?.classList.remove(this.current)
document.querySelector("body")?.classList.add(theme)
this.current = theme
this.icon = this.getIcon(theme)
this.subject$.next(theme)
localStorage.setItem("theme", theme)
}
getIcon(theme: Theme): string {
switch (theme) {
case Theme.Dark:
return "brightness_high"
case Theme.Light:
default:
return "brightness_low"
}
}
}

View File

@ -1,18 +1,23 @@
[ [
"https://ipfs.io/:type/:hash", "https://ipfs.io/:type/:hash",
"https://dweb.link/:type/:hash",
"https://gateway.ipfs.io/:type/:hash", "https://gateway.ipfs.io/:type/:hash",
"https://ipfs.infura.io/:type/:hash", "https://ipfs.infura.io/:type/:hash",
"https://infura-ipfs.io/:type/:hash", "https://rx14.co.uk/:type/:hash",
"https://ninetailed.ninja/:type/:hash", "https://ninetailed.ninja/:type/:hash",
"https://via0.com/:type/:hash", "https://ipfs.globalupload.io/:hash",
"https://ipfs.jes.xxx/:type/:hash",
"https://siderus.io/:type/:hash",
"https://eu.siderus.io/:type/:hash",
"https://na.siderus.io/:type/:hash",
"https://ap.siderus.io/:type/:hash",
"https://10.via0.com/:type/:hash",
"https://ipfs.eternum.io/:type/:hash", "https://ipfs.eternum.io/:type/:hash",
"https://hardbin.com/:type/:hash", "https://hardbin.com/:type/:hash",
"https://ipfs.wa.hle.rs/:type/:hash",
"https://gateway.blocksec.com/:type/:hash", "https://gateway.blocksec.com/:type/:hash",
"https://ipfs.renehsz.com/:type/:hash",
"https://cloudflare-ipfs.com/:type/:hash", "https://cloudflare-ipfs.com/:type/:hash",
"https://astyanax.io/:type/:hash", "https://ipns.co/:hash",
"https://cf-ipfs.com/:type/:hash",
"https://ipns.co/:type/:hash",
"https://ipfs.mrh.io/:type/:hash", "https://ipfs.mrh.io/:type/:hash",
"https://gateway.originprotocol.com/:type/:hash", "https://gateway.originprotocol.com/:type/:hash",
"https://gateway.pinata.cloud/:type/:hash", "https://gateway.pinata.cloud/:type/:hash",
@ -21,76 +26,14 @@
"https://ipfs.busy.org/:type/:hash", "https://ipfs.busy.org/:type/:hash",
"https://ipfs.greyh.at/:type/:hash", "https://ipfs.greyh.at/:type/:hash",
"https://gateway.serph.network/:type/:hash", "https://gateway.serph.network/:type/:hash",
"https://jorropo.net/:type/:hash", "https://jorropo.ovh/:type/:hash",
"https://gateway.temporal.cloud/:type/:hash",
"https://ipfs.fooock.com/:type/:hash", "https://ipfs.fooock.com/:type/:hash",
"https://cdn.cwinfo.net/:type/:hash", "https://cdn.cwinfo.net/:type/:hash",
"https://aragon.ventures/:type/:hash", "https://ipfs.privacytools.io/:type/:hash",
"https://ipfs-cdn.aragon.ventures/:type/:hash", "https://ipfs.jeroendeneef.com/:type/:hash",
"https://permaweb.io/:type/:hash", "https://permaweb.io/:type/:hash",
"https://ipfs.stibarc.gq/:type/:hash",
"https://ipfs.best-practice.se/:type/:hash", "https://ipfs.best-practice.se/:type/:hash",
"https://storjipfs-gateway.com/:type/:hash", "https://lineageos-on-ipfs.com/:type/:hash"
"https://ipfs.runfission.com/:type/:hash",
"https://ipfs.trusti.id/:type/:hash",
"https://ipfs.overpi.com/:type/:hash",
"https://gateway.ipfs.lc/:type/:hash",
"https://ipfs.ink/:type/:hash",
"https://ipfsgateway.makersplace.com/:type/:hash",
"https://gateway.ravenland.org/:type/:hash",
"https://ipfs.funnychain.co/:type/:hash",
"https://ipfs.telos.miami/:type/:hash",
"https://ipfs.mttk.net/:type/:hash",
"https://ipfs.fleek.co/:type/:hash",
"https://ipfs.jbb.one/:type/:hash",
"https://ipfs.yt/:type/:hash",
"https://hashnews.k1ic.com/:type/:hash",
"https://ipfs.vip/:type/:hash",
"https://ipfs.drink.cafe/:type/:hash",
"https://ipfs.azurewebsites.net/:type/:hash",
"https://gw.ipfspin.com/:type/:hash",
"https://ipfs.kavin.rocks/:type/:hash",
"https://ipfs.denarius.io/:type/:hash",
"https://ipfs.mihir.ch/:type/:hash",
"https://crustwebsites.net/:type/:hash",
"https://ipfs0.sjc.cloudsigma.com/:type/:hash",
"http://ipfs.genenetwork.org/:type/:hash",
"https://ipfs.eth.aragon.network/:type/:hash",
"https://ipfs.smartholdem.io/:type/:hash",
"https://ipfs.xoqq.ch/:type/:hash",
"https://natoboram.mynetgear.com/:type/:hash",
"https://video.oneloveipfs.com/:type/:hash",
"http://ipfs.anonymize.com/:type/:hash",
"https://ipfs.taxi/:type/:hash",
"https://ipfs.scalaproject.io/:type/:hash",
"https://search.ipfsgate.com/:type/:hash",
"https://ipfs.decoo.io/:type/:hash",
"https://ivoputzer.xyz/:type/:hash",
"https://alexdav.id/:type/:hash",
"https://ipfs.uploads.nu/:type/:hash",
"https://hub.textile.io/:type/:hash",
"https://ipfs1.pixura.io/:type/:hash",
"https://ravencoinipfs-gateway.com/:type/:hash",
"https://konubinix.eu/:type/:hash",
"https://3cloud.ee/:type/:hash",
"https://ipfs.tubby.cloud/:type/:hash",
"https://ipfs.lain.la/:type/:hash",
"https://ipfs.adatools.io/:type/:hash",
"https://ipfs.kaleido.art/:type/:hash",
"https://ipfs.slang.cx/:type/:hash",
"https://ipfs.arching-kaos.com/:type/:hash",
"https://storry.tv/:type/:hash",
"https://ipfs.kxv.io/:type/:hash",
"https://ipfs.1-2.dev/:type/:hash",
"https://ipfs-nosub.stibarc.com/:type/:hash",
"https://dweb.eu.org/:type/:hash",
"https://permaweb.eu.org/:type/:hash",
"https://ipfs.namebase.io/:type/:hash",
"https://ipfs.tribecap.co/:type/:hash",
"https://ipfs.kinematiks.com/:type/:hash",
"https://c4rex.co/:type/:hash",
"https://ipfs.zod.tv/:type/:hash",
"https://nftstorage.link/:type/:hash",
"https://gravity.jup.io/:type/:hash",
"http://fzdqwfb5ml56oadins5jpuhe6ki6bk33umri35p5kt2tue4fpws5efid.onion/:type/:hash",
"https://tth-ipfs.com/:type/:hash",
"https://:type.natoboram.com/:type/:hash"
] ]

View File

@ -1,7 +1,7 @@
import type { Environment } from "../app/interfaces/environment" import { Environment } from '../app/interfaces/environment';
export const environment: Environment = { export const environment: Environment = {
production: true, production: true,
base_href: "/public-gateway-cacher", base_href: '/public-gateway-cacher',
useHash: false, useHash: false,
} };

View File

@ -1,6 +1,6 @@
import type { Environment } from "../app/interfaces/environment" import { Environment } from '../app/interfaces/environment';
export const environment: Environment = { export const environment: Environment = {
production: true, production: true,
useHash: true, useHash: true,
} };

View File

@ -1,7 +1,7 @@
import type { Environment } from "../app/interfaces/environment" import { Environment } from '../app/interfaces/environment';
export const environment: Environment = { export const environment: Environment = {
production: true, production: true,
base_href: "/", base_href: '/',
useHash: false, useHash: false,
} };

View File

@ -1,4 +1,4 @@
import type { Environment } from "../app/interfaces/environment" import { Environment } from '../app/interfaces/environment';
// This file can be replaced during build by using the `fileReplacements` array. // This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
@ -6,9 +6,9 @@ import type { Environment } from "../app/interfaces/environment"
export const environment: Environment = { export const environment: Environment = {
production: false, production: false,
base_href: "/", base_href: '/',
useHash: false, useHash: false,
} };
/* /*
* For easier debugging in development mode, you can import the following file * For easier debugging in development mode, you can import the following file
@ -17,4 +17,4 @@ export const environment: Environment = {
* This import should be commented out in production mode because it will have a negative impact * This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown. * on performance if an error is thrown.
*/ */
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. // import 'zone.js/dist/zone-error'; // Included with Angular CLI.

View File

@ -1,23 +1,29 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<meta charset="utf-8" /> <head>
<meta charset="utf-8">
<title>Public Gateway Cacher</title> <title>Public Gateway Cacher</title>
<!-- IPFS --> <!-- IPFS -->
<script> <script>
if (document.getElementsByTagName("base").length === 0) document.write('<base href="' + window.location.pathname + '"/>') if (document.getElementsByTagName('base').length === 0) document.write('<base href="' + window.location.pathname + '"/>');
</script> </script>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.png" /> <link rel="icon" type="image/x-icon" href="favicon.png">
<!-- Material --> <!-- Material -->
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" /> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body class="mat-app-background theme-light"> <!-- IPFS-CSS -->
<link href="assets/ipfs-css/ipfs.css" rel="stylesheet">
</head>
<body>
<app-root></app-root> <app-root></app-root>
</body> </body>
</html> </html>

View File

@ -1,12 +1,12 @@
import { enableProdMode } from "@angular/core" import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic" import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from "./app/app.module" import 'hammerjs';
import { environment } from "./environments/environment" import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) { if (environment.production) {
enableProdMode() enableProdMode();
} }
platformBrowserDynamic() platformBrowserDynamic().bootstrapModule(AppModule)
.bootstrapModule(AppModule) .catch(err => console.error(err));
.catch((err): void => console.error(err))

View File

@ -18,6 +18,16 @@
* BROWSER POLYFILLS * BROWSER POLYFILLS
*/ */
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/** /**
* By default, zone.js will patch all possible macroTask and DomEvents * By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags * user can disable parts of macroTask/DomEvents patch by setting following flags
@ -45,7 +55,8 @@
/*************************************************************************************************** /***************************************************************************************************
* Zone JS is required by default for Angular itself. * Zone JS is required by default for Angular itself.
*/ */
import "zone.js" // Included with Angular CLI. import 'zone.js/dist/zone'; // Included with Angular CLI.
/*************************************************************************************************** /***************************************************************************************************
* APPLICATION IMPORTS * APPLICATION IMPORTS

View File

@ -1,39 +1,29 @@
// Custom Theming for Angular Material // Custom Theming for Angular Material
@use "@angular/material" as mat;
// For more information: https://material.angular.io/guide/theming // For more information: https://material.angular.io/guide/theming
@import '~@angular/material/theming';
// Plus imports for other components in your app. // Plus imports for other components in your app.
// Include the common styles for Angular Material. We include this here so that you only // Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app. // have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once! // Be sure that you only ever include this mixin once!
@include mat.core(); @include mat-core();
// // Define the palettes for your theme using the Material Design palettes available in palette.scss // Define the palettes for your theme using the Material Design palettes available in palette.scss
// // (imported above). For each palette, you can optionally specify a default, lighter, and darker // (imported above). For each palette, you can optionally specify a default, lighter, and darker
// // hue. Available color palettes: https://material.io/design/color/ // hue. Available color palettes: https://material.io/design/color/
// $public-gateway-cacher-primary: mat-palette($mat-indigo); $public-gateway-cacher-primary: mat-palette($mat-indigo);
// $public-gateway-cacher-accent: mat-palette($mat-pink, A200, A100, A400); $public-gateway-cacher-accent: mat-palette($mat-pink, A200, A100, A400);
// // The warn palette is optional (defaults to red). // The warn palette is optional (defaults to red).
// $public-gateway-cacher-warn: mat-palette($mat-red); $public-gateway-cacher-warn: mat-palette($mat-red);
// // Create the theme object (a Sass map containing all of the palettes). // Create the theme object (a Sass map containing all of the palettes).
// $public-gateway-cacher-theme: mat-light-theme($public-gateway-cacher-primary, $public-gateway-cacher-accent, $public-gateway-cacher-warn); $public-gateway-cacher-theme: mat-light-theme($public-gateway-cacher-primary, $public-gateway-cacher-accent, $public-gateway-cacher-warn);
// // Include theme styles for core and each component used in your app. // Include theme styles for core and each component used in your app.
// // Alternatively, you can import and @include the theme mixins for each component // Alternatively, you can import and @include the theme mixins for each component
// // that you are using. // that you are using.
// @include angular-material-theme($public-gateway-cacher-theme); @include angular-material-theme($public-gateway-cacher-theme);
@import "styles/ipfs-themes.scss";
.theme-light {
@include mat.all-component-themes($ipfs-light-theme);
}
.theme-dark {
@include mat.all-component-themes($ipfs-dark-theme);
}
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
@ -47,5 +37,4 @@ body {
font-family: Roboto, "Helvetica Neue", sans-serif; font-family: Roboto, "Helvetica Neue", sans-serif;
} }
@import "~bootstrap/scss/bootstrap-grid.scss"; @import '~bootstrap/scss/bootstrap-grid.scss';
@import "~ipfs-css/theme.scss";

View File

@ -1,34 +0,0 @@
@import "@angular/material/core/theming/palette";
$ipfs-colour-navy: (
default: #0b3a53,
lighter: #3e6480,
darker: #00142a,
contrast: (
default: $light-primary-text,
lighter: $light-primary-text,
darker: $light-primary-text,
),
);
$ipfs-colour-aqua: (
default: #69c5cd,
lighter: #9df8ff,
darker: #32949c,
contrast: (
default: $dark-primary-text,
lighter: $dark-primary-text,
darker: $dark-primary-text,
),
);
$ipfs-colour-yellow: (
default: #f39021,
lighter: #ffc155,
darker: #bb6200,
contrast: (
default: $dark-primary-text,
lighter: $dark-primary-text,
darker: $dark-primary-text,
),
);

View File

@ -1,6 +0,0 @@
@use "@angular/material" as mat;
@import "ipfs-colours.scss";
$ipfs-primary: mat.define-palette($ipfs-colour-navy, "default", "lighter", "darker");
$ipfs-accent: mat.define-palette($ipfs-colour-aqua, "default", "lighter", "darker");
$ipfs-warn: mat.define-palette($ipfs-colour-yellow, "default", "lighter", "darker");

View File

@ -1,5 +0,0 @@
@use "@angular/material" as mat;
@import "ipfs-palettes.scss";
$ipfs-light-theme: mat.define-light-theme($ipfs-primary, $ipfs-accent, $ipfs-warn);
$ipfs-dark-theme: mat.define-dark-theme($ipfs-primary, $ipfs-accent, $ipfs-warn);

View File

@ -1,16 +1,20 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files // This file is required by karma.conf.js and loads recursively all the .spec and framework files
import "zone.js/testing"
import { getTestBed } from "@angular/core/testing" import 'zone.js/dist/zone-testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from "@angular/platform-browser-dynamic/testing" import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any declare const require: any;
// First, initialize the Angular testing environment. // First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: false } }) getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests. // Then we find all the tests.
const context = require.context("./", true, /\.spec\.ts$/) const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules. // And load the modules.
context.keys().map(context) context.keys().map(context);

View File

@ -1,10 +1,17 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/app", "outDir": "./out-tsc/app",
"types": [] "types": []
}, },
"files": ["src/main.ts", "src/polyfills.ts"], "files": [
"include": ["src/**/*.d.ts"] "src/main.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.d.ts"
],
"angularCompilerOptions": {
"enableIvy": false
}
} }

View File

@ -1,40 +1,26 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"compileOnSave": false, "compileOnSave": false,
"compilerOptions": { "compilerOptions": {
"baseUrl": "./", "baseUrl": "./",
"outDir": "./dist/out-tsc", "outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"sourceMap": true, "sourceMap": true,
"declaration": false, "declaration": false,
"downlevelIteration": true, "downlevelIteration": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node", "moduleResolution": "node",
"importHelpers": true, "importHelpers": true,
"target": "ESNext", "target": "es2015",
"module": "ESNext", "typeRoots": [
"lib": ["ESNext", "DOM"] "node_modules/@types"
],
"lib": [
"es2018",
"dom"
]
}, },
"angularCompilerOptions": { "angularCompilerOptions": {
"fullTemplateTypeCheck": true, "fullTemplateTypeCheck": true,
"strictInjectionParameters": true, "strictInjectionParameters": true
"strictTemplates": true
} }
} }

View File

@ -1,10 +1,21 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/spec", "outDir": "./out-tsc/spec",
"types": ["jasmine"] "types": [
"jasmine",
"node"
]
}, },
"files": ["src/test.ts", "src/polyfills.ts"], "files": [
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"] "src/test.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
],
"angularCompilerOptions": {
"enableIvy": false
}
} }

279
tslint.json Normal file
View File

@ -0,0 +1,279 @@
{
"extends": [
"tslint:recommended",
"rxjs-tslint-rules"
],
"rules": {
"array-type": false,
"arrow-parens": false,
"deprecation": {
"severity": "warning"
},
"component-class-suffix": true,
"contextual-lifecycle": true,
"directive-class-suffix": true,
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"import-blacklist": [
true,
"rxjs/Rx"
],
"interface-name": false,
"max-classes-per-file": false,
"max-line-length": [
true,
{
"limit": 140,
"ignore-pattern": "^import |^export {(.*?)}|class [a-zA-Z]+ implements |// "
}
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"public-static-field",
"private-static-field",
"public-instance-field",
"private-instance-field",
"public-constructor",
"private-constructor",
"public-instance-method",
"protected-instance-method",
"private-instance-method",
"public-static-method",
"protected-static-method",
"private-static-method"
]
}
],
"no-consecutive-blank-lines": [
true,
1
],
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-empty": [
true,
"allow-empty-functions"
],
"no-inferrable-types": [
true,
"ignore-params"
],
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-switch-case-fall-through": true,
"no-use-before-declare": true,
"no-var-requires": false,
"object-literal-key-quotes": [
true,
"as-needed"
],
"object-literal-sort-keys": false,
"ordered-imports": false,
"quotemark": [
true,
"single"
],
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"origin-ordered-imports": [
true
],
"rx-subject-restrictions": true,
"ban-types": [
true,
[
"Object",
"Use {} instead."
],
[
"String"
]
],
"no-unnecessary-class": [
true,
"allow-constructor-only",
"allow-static-only",
"allow-empty-class"
],
"no-for-in-array": true,
"typedef": [
true,
"call-signature",
"property-declaration",
"object-destructuring",
"arrow-call-signature"
],
"no-unused": true,
"no-return-undefined": true,
"no-collapsible-if": true,
"arrow-return-shorthand": [
true,
"multiline"
],
"no-static-this": true,
"template-use-track-by-function": true,
"prefer-template": true,
"contextual-decorator": false,
"no-pipe-impure": true,
"component-max-inline-declarations": true,
"no-attribute-decorator": true,
"no-forward-ref": true,
"no-lifecycle-call": true,
"template-no-call-expression": true,
"no-unused-css": true,
"prefer-output-readonly": true,
"template-conditional-complexity": true,
"use-pipe-decorator": true,
"use-component-view-encapsulation": true,
"no-queries-metadata-property": true,
"prefer-inline-decorator": false,
"import-destructuring-spacing": true,
"newline-before-return": false,
"no-trailing-whitespace": true,
"space-within-parens": true,
"space-before-function-paren": [
true,
{
"anonymous": "never",
"named": "never",
"asyncArrow": "always",
"method": "never",
"constructor": "never"
}
],
"max-file-line-count": [
true,
400
],
"cyclomatic-complexity": [
true,
20
],
"encoding": true,
"no-unsafe-finally": true,
"no-duplicate-switch-case": true,
"increment-decrement": [
true,
"allow-post"
],
"triple-equals": [
true,
"allow-null-check"
],
"no-invalid-template-strings": true,
"no-unnecessary-type-assertion": true,
"callable-types": true,
"no-reference": true,
"no-default-import": true,
"no-default-export": true,
"no-require-imports": true,
"no-duplicate-imports": true,
"no-import-side-effect": [
true,
{
"ignore-module": "(hammerjs|core-js|zone.js)"
}
],
"no-implicit-dependencies": [
true,
"dev"
],
"no-unnecessary-initializer": true,
"no-var-keyword": true,
"prefer-const": true,
"no-return-await": true,
"no-unnecessary-callback-wrapper": true,
"no-arg": true,
"eofline": true,
"no-tautology-expression": true,
"use-isnan": true,
"restrict-plus-operands": true,
"no-this-assignment": true,
"no-invalid-this": [
true,
"check-function-in-method"
],
"no-unbound-method": true,
"prefer-readonly": true,
"radix": false,
"no-misused-new": true,
"no-duplicate-super": true,
"rxjs-no-compat": true,
"rxjs-no-internal": true,
"unnecessary-else": [
true,
{
"allow-else-if": true
}
],
"no-any": [
true,
{
"ignore-rest-args": true
}
],
"variable-name": {
"options": [
"ban-keywords",
"check-format",
"allow-leading-underscore",
"allow-pascal-case"
]
},
"trailing-comma": [
true,
{
"multiline": {
"objects": "ignore",
"arrays": "ignore",
"functions": "never",
"typeLiterals": "ignore"
},
"esSpecCompliant": true
}
]
},
"rulesDirectory": [
"codelyzer",
"node_modules/tslint-origin-ordered-imports-rule/dist",
"node_modules/tslint-rxjs-subject-restrictions-rule/dist",
"node_modules/tslint-consistent-codestyle/rules"
],
"linterOptions": {
"exclude": [
"**/*-routing.module.ts",
"src/polyfills.ts",
"src/test.ts",
"**/*.po.ts"
]
}
}

8135
yarn.lock Normal file

File diff suppressed because it is too large Load Diff