diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6f8041d7..824c3e9d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -28,7 +28,7 @@ It is also always helpful to have some context for your pull request. What was t Use the feature request board to submit new ideas and vote on which ideas should be integrated first. -:triangular_flag_on_post: [https://wiki.js.org/feedback/](https://wiki.js.org/feedback/) +:triangular_flag_on_post: [https://js.wiki/feedback/](https://js.wiki/feedback/) *Do not use GitHub issues to submit new feature ideas, as it will closed and you'll be asked to use the feature request board above. GitHub Issues are limited to bugs / issues / help*. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 3b4b7ae9..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,12 +0,0 @@ - - -### Actual behavior - -### Expected behavior - -### Steps to reproduce the behavior - - - - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 680ec362..90c15174 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,9 +3,6 @@ contact_links: - name: Help / Questions url: https://github.com/Requarks/wiki/discussions/categories/help-questions about: Ask the community for help on using or setting up Wiki.js - - name: Report a Security Issue - url: https://github.com/Requarks/wiki/security/policy - about: Privately report security issues so they can be addressed quickly. - name: Errors / Bug Reports url: https://github.com/Requarks/wiki/discussions/categories/error-bug-report about: Create a discussion around the bug / error you're getting. If validated, a proper GitHub issue will be created so that it can be worked on. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a5b6702a..924101cb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: packages: write steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set Build Variables run: | @@ -42,20 +42,20 @@ jobs: cat package.json - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker images - uses: docker/build-push-action@v2.9.0 + uses: docker/build-push-action@v5 with: context: . file: dev/build/Dockerfile @@ -77,7 +77,7 @@ jobs: find _dist/wiki/ -printf "%P\n" | tar -czf wiki-js.tar.gz --no-recursion -C _dist/wiki/ -T - - name: Upload a Build Artifact - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v4 with: name: drop path: wiki-js.tar.gz @@ -92,7 +92,7 @@ jobs: dbtype: [postgres, mysql, mariadb, mssql, sqlite] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set Test Variables run: | @@ -129,7 +129,7 @@ jobs: docker: armv7 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set Version Variables run: | @@ -142,26 +142,26 @@ jobs: fi - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Download a Build Artifact - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v4 with: name: drop path: drop @@ -172,11 +172,12 @@ jobs: tar -xzf $GITHUB_WORKSPACE/drop/wiki-js.tar.gz -C $GITHUB_WORKSPACE/build --exclude=node_modules - name: Build and push Docker images - uses: docker/build-push-action@v2.9.0 + uses: docker/build-push-action@v5 with: context: . file: dev/build-arm/Dockerfile platforms: ${{ matrix.platform }} + provenance: false push: true tags: | requarks/wiki:canary-${{ matrix.docker }}-${{ env.REL_VERSION_STRICT }} @@ -189,12 +190,12 @@ jobs: steps: - name: Setup Node.js environment - uses: actions/setup-node@v2.5.1 + uses: actions/setup-node@v4 with: - node-version: 12.x + node-version: 18.x - name: Download a Build Artifact - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v4 with: name: drop path: drop @@ -202,17 +203,25 @@ jobs: - name: Extract Build run: | mkdir -p win - tar -xzf $env:GITHUB_WORKSPACE\drop\wiki-js.tar.gz -C $env:GITHUB_WORKSPACE\win --exclude=node_modules + tar -xzf $env:GITHUB_WORKSPACE\drop\wiki-js.tar.gz -C $env:GITHUB_WORKSPACE\win + Copy-Item win\node_modules\extract-files\package.json patch-extractfile.json -Force + Remove-Item -Path win\node_modules -Force -Recurse - name: Install Dependencies - run: yarn --production --frozen-lockfile --non-interactive + run: | + yarn --production --frozen-lockfile --non-interactive + yarn patch-package working-directory: win + - name: Fix patched packages + run: | + Copy-Item patch-extractfile.json win\node_modules\extract-files\package.json -Force + - name: Create Bundle run: tar -czf wiki-js-windows.tar.gz -C $env:GITHUB_WORKSPACE\win . - name: Upload a Build Artifact - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v4 with: name: drop-win path: wiki-js-windows.tar.gz @@ -232,13 +241,13 @@ jobs: echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -273,13 +282,13 @@ jobs: echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -319,13 +328,13 @@ jobs: docker manifest push -p ghcr.io/requarks/wiki:latest - name: Download Linux Build - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v4 with: name: drop path: drop - name: Download Windows Build - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v4 with: name: drop-win path: drop-win @@ -339,17 +348,18 @@ jobs: writeToFile: false - name: Update GitHub Release - uses: ncipollo/release-action@v1 + uses: ncipollo/release-action@v1.12.0 with: allowUpdates: true draft: false + makeLatest: true name: ${{ github.ref_name }} body: ${{ steps.changelog.outputs.changes }} token: ${{ github.token }} artifacts: 'drop/wiki-js.tar.gz,drop-win/wiki-js-windows.tar.gz' - + - name: Notify Slack Releases Channel - uses: slackapi/slack-github-action@v1.18.0 + uses: slackapi/slack-github-action@v1.26.0 with: payload: | { @@ -359,29 +369,46 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - build-do-image: - name: Build DigitalOcean Image - runs-on: ubuntu-latest - needs: [release] - - steps: - - uses: actions/checkout@v2 - - - name: Set Version Variables - run: | - echo "Using TAG mode: $GITHUB_REF_NAME" - echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV - - - name: Install Packer - run: | - curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - - sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" - sudo apt-get update && sudo apt-get install packer - - - name: Build Droplet Image - env: - DIGITALOCEAN_API_TOKEN: ${{ secrets.DO_TOKEN }} - WIKI_APP_VERSION: ${{ env.REL_VERSION_STRICT }} - working-directory: dev/packer - run: | - packer build digitalocean.json + - name: Notify Telegram Channel + uses: appleboy/telegram-action@v0.1.1 + with: + to: ${{ secrets.TELEGRAM_TO }} + token: ${{ secrets.TELEGRAM_TOKEN }} + format: markdown + disable_web_page_preview: true + message: | + Wiki.js *${{ github.ref_name }}* has been released! + See [release notes](https://github.com/requarks/wiki/releases) for details. + + - name: Notify Discord Channel + uses: sebastianpopp/discord-action@v2.0 + with: + webhook: ${{ secrets.DISCORD_WEBHOOK }} + message: Wiki.js ${{ github.ref_name }} has been released! See https://github.com/requarks/wiki/releases for details. + + # build-do-image: + # name: Build DigitalOcean Image + # runs-on: ubuntu-latest + # needs: [release] + + # steps: + # - uses: actions/checkout@v4 + + # - name: Set Version Variables + # run: | + # echo "Using TAG mode: $GITHUB_REF_NAME" + # echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV + + # - name: Install Packer + # run: | + # curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - + # sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" + # sudo apt-get update && sudo apt-get install packer + + # - name: Build Droplet Image + # env: + # DIGITALOCEAN_API_TOKEN: ${{ secrets.DO_TOKEN }} + # WIKI_APP_VERSION: ${{ env.REL_VERSION_STRICT }} + # working-directory: dev/packer + # run: | + # packer build digitalocean.json diff --git a/.nvmrc b/.nvmrc index 0c6886ca..860cc500 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v12.16.3 +v18.17.1 diff --git a/.vscode/settings.json b/.vscode/settings.json index dc1a054c..75e3a447 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,7 @@ "vue" ], "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "i18n-ally.localesPaths": [ "server/locales" diff --git a/README.md b/README.md index b1d5ac24..468ddd8c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@
-Wiki.js + + + Wiki.js + [![Release](https://img.shields.io/github/release/Requarks/wiki.svg?style=flat&maxAge=3600)](https://github.com/Requarks/wiki/releases) [![License](https://img.shields.io/badge/license-AGPLv3-blue.svg?style=flat)](https://github.com/requarks/wiki/blob/master/LICENSE) @@ -12,9 +15,10 @@ [![GitHub Sponsors](https://img.shields.io/github/sponsors/ngpixel?logo=github&color=ea4aaa)](https://github.com/users/NGPixel/sponsorship) [![Open Collective backers and sponsors](https://img.shields.io/opencollective/all/wikijs?label=backers&color=218bff&logo=opencollective&logoColor=white)](https://opencollective.com/wikijs) [![Chat on Slack](https://img.shields.io/badge/slack-requarks-CC2B5E.svg?style=flat&logo=slack)](https://wiki.requarks.io/slack) -[![Twitter Follow](https://img.shields.io/badge/follow-%40requarks-blue.svg?style=flat&logo=twitter)](https://twitter.com/requarks) +[![Follow on Twitter](https://img.shields.io/badge/twitter-%40requarks-blue.svg?style=flat&logo=twitter&logoColor=white)](https://twitter.com/requarks) +[![Follow on Telegram](https://img.shields.io/badge/telegram-%40wiki__js-blue.svg?style=flat&logo=telegram)](https://t.me/wiki_js) +[![Chat on Discord](https://img.shields.io/badge/discord-join-8D96F6.svg?style=flat&logo=discord&logoColor=white)](https://discord.gg/rcxt9QS2jd) [![Reddit](https://img.shields.io/badge/reddit-%2Fr%2Fwikijs-orange?logo=reddit&logoColor=white)](https://www.reddit.com/r/wikijs/) -[![Subscribe to Newsletter](https://img.shields.io/badge/newsletter-subscribe-yellow.svg?style=flat&logo=mailchimp)](https://blog.js.wiki/subscribe) ##### A modern, lightweight and powerful wiki app built on NodeJS @@ -39,7 +43,7 @@
-Wiki.js is an open source project that has been made possible due to the generous contributions by community [backers](https://wiki.js.org/about). If you are interested in supporting this project, please consider [becoming a sponsor](https://github.com/users/NGPixel/sponsorship), [becoming a patron](https://www.patreon.com/requarks), donating to our [OpenCollective](https://opencollective.com/wikijs), via [Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FLV5X255Z9CJU&source=url) or via Ethereum (`0xe1d55c19ae86f6bcbfb17e7f06ace96bdbb22cb5`). +Wiki.js is an open source project that has been made possible due to the generous contributions by community [backers](https://js.wiki/about). If you are interested in supporting this project, please consider [becoming a sponsor](https://github.com/users/NGPixel/sponsorship), [becoming a patron](https://www.patreon.com/requarks), donating to our [OpenCollective](https://opencollective.com/wikijs), via [Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FLV5X255Z9CJU&source=url) or via Ethereum (`0xe1d55c19ae86f6bcbfb17e7f06ace96bdbb22cb5`). [![Become a Sponsor](https://img.shields.io/badge/donate-github-ea4aaa.svg?style=popout&logo=github)](https://github.com/users/NGPixel/sponsorship) [![Become a Patron](https://img.shields.io/badge/donate-patreon-orange.svg?style=popout&logo=patreon)](https://www.patreon.com/requarks) @@ -80,11 +84,6 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - - - - - @@ -94,6 +93,11 @@ Support this project by becoming a sponsor. Your name will show up in the Contri + + + + - +
+ + + + Alexander Casassovici
(@alexksso) @@ -114,6 +118,13 @@ Support this project by becoming a sponsor. Your name will show up in the Contri
+ + + +
Jay Daley
(@JayDaley) @@ -124,11 +135,26 @@ Support this project by becoming a sponsor. Your name will show up in the Contri Oleksii
(@idokka)
@@ -137,22 +163,27 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - Akira Suenami ([@a-suenami](https://github.com/a-suenami)) +- Armin Reiter ([@arminreiter](https://github.com/arminreiter)) - Arnaud Marchand ([@snuids](https://github.com/snuids)) - Brian Douglass ([@bhdouglass](https://github.com/bhdouglass)) - Bryon Vandiver ([@asterick](https://github.com/asterick)) - Cameron Steele ([@ATechAdventurer](https://github.com/ATechAdventurer)) - Charlie Schliesser ([@charlie-s](https://github.com/charlie-s)) - Cloud Data Hosting LLC ([@CloudDataHostingLLC](https://github.com/CloudDataHostingLLC)) +- Cole Manning ([@RVRX](https://github.com/RVRX)) - CrazyMarvin ([@CrazyMarvin](https://github.com/CrazyMarvin)) +- Daniel Horner ([@danhorner](https://github.com/danhorner)) - David Christian Holin ([@SirGibihm](https://github.com/SirGibihm)) - Dragan Espenschied ([@despens](https://github.com/despens)) - Elijah Zobenko ([@he110](https://github.com/he110)) +- Emerson-Perna ([@Emerson-Perna](https://github.com/Emerson-Perna)) - Ernie ([@iamernie](https://github.com/iamernie)) - Fabio Ferrari ([@devxops](https://github.com/devxops)) - Finsa S.p.A. ([@finsaspa](https://github.com/finsaspa)) - Florian Moss ([@florianmoss](https://github.com/florianmoss)) - GoodCorporateCitizen ([@GoodCorporateCitizen](https://github.com/GoodCorporateCitizen)) - HeavenBay ([@HeavenBay](https://github.com/heavenbay)) +- HikaruEgashira ([@HikaruEgashira](https://github.com/HikaruEgashira)) - Ian Hyzy ([@ianhyzy](https://github.com/ianhyzy)) - Jaimyn Mayer ([@jabelone](https://github.com/jabelone)) - Jay Lee ([@polyglotm](https://github.com/polyglotm)) @@ -162,32 +193,42 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - Marcilio Leite Neto ([@marclneto](https://github.com/marclneto)) - Mattias Johnson ([@mattiasJohnson](https://github.com/mattiasJohnson)) - Max Ricketts-Uy ([@MaxRickettsUy](https://github.com/MaxRickettsUy)) +- Mickael Asseline ([@PAPAMICA](https://github.com/PAPAMICA)) +- Mitchell Rowton ([@mrowton](https://github.com/mrowton)) - -- Mickael Asseline ([@PAPAMICA](https://github.com/PAPAMICA)) -- Mitchell Rowton ([@mrowton](https://github.com/mrowton)) + - M. Scott Ford ([@mscottford](https://github.com/mscottford)) - Nick Halase ([@nhalase](https://github.com/nhalase)) - Nick Price ([@DominoTree](https://github.com/DominoTree)) - Nina Reynolds ([@cutecycle](https://github.com/cutecycle)) - Noel Cower ([@nilium](https://github.com/nilium)) - Oleksandr Koltsov ([@crambo](https://github.com/crambo)) +- Phi Zeroth ([@phizeroth](https://github.com/phizeroth)) - Philipp Schmitt ([@pschmitt](https://github.com/pschmitt)) - Robert Lanzke ([@winkelement](https://github.com/winkelement)) +- Ruizhe Li ([@liruizhe1995](https://github.com/liruizhe1995)) - Sam Martin ([@ABitMoreDepth](https://github.com/ABitMoreDepth)) - Sean Coffey ([@seanecoffey](https://github.com/seanecoffey)) +- Simon Ott ([@ottsimon](https://github.com/ottsimon)) - Stephan Kristyn ([@stevek-pro](https://github.com/stevek-pro)) - Theodore Chu ([@TheodoreChu](https://github.com/TheodoreChu)) +- Tim Elmer ([@tim-elmer](https://github.com/tim-elmer)) - Tyler Denman ([@tylerguy](https://github.com/tylerguy)) - Victor Bilgin ([@vbilgin](https://github.com/vbilgin)) - VMO Solutions ([@vmosolutions](https://github.com/vmosolutions)) +- YazMogg35 ([@YazMogg35](https://github.com/YazMogg35)) +- Yu Yongwoo ([@uyu423](https://github.com/uyu423)) +- ameyrakheja ([@ameyrakheja](https://github.com/ameyrakheja)) - aniketpanjwani ([@aniketpanjwani](https://github.com/aniketpanjwani)) - aytaa ([@aytaa](https://github.com/aytaa)) +- cesar ([@cesarnr21](https://github.com/cesarnr21)) - chaee ([@chaee](https://github.com/chaee)) +- lwileczek ([@lwileczek](https://github.com/lwileczek)) - magicpotato ([@fortheday](https://github.com/fortheday)) - motoacs ([@motoacs](https://github.com/motoacs)) +- muzian666 ([@muzian666](https://github.com/muzian666)) - rburckner ([@rburckner](https://github.com/rburckner)) - scorpion ([@scorpion](https://github.com/scorpion)) - valantien ([@valantien](https://github.com/valantien)) @@ -338,6 +379,23 @@ Support this project by becoming a sponsor. Your logo will show up in the Contri + + + + + + + + + + + + + + + + +
@@ -350,15 +408,21 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re
+- Aeternum - Al Romano - Alex Balabanov +- Alex Milanov - Alex Zen - Arti Zirk +- Ave - Brandon Curtis +- Damien Hottelier +- Daniel T. Holtzclaw - Dave 'Sri' Seah - djagoo - dz - Douglas Lassance +- Ergoflix - Ernie Reid - Etienne - Flemis Jurgenheimer @@ -368,26 +432,34 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re - Hope - Ian - Imari Childress +- Iskander Callos -- Iskander Callos - Josh Stewart - Justin Dunsworth - Keir - Loïc CRAMPON - Ludgeir Ibanez +- Lyn Matten +- Mads Rosendahl - Mark Mansur - Matt Gedigian +- Mike Ditton - Nate Figz - Patryk +- Paul O'Fallon - Philipp Schürch - Tracey Duffy +- Quaxim - Richeir +- Sergio Navarro Fernández - Shad Narcher +- ShadowVoyd - SmartNET.works - Stepan Sokolovskyi +- Zach Crawford - Zach Maynard - 张白驹 @@ -407,9 +479,6 @@ This project exists thanks to all the people who contribute. [[Contribute]](http

Special Thanks

-![Algolia](https://js.wiki/legacy/logo_algolia.png) -[Algolia](https://www.algolia.com/) for providing access to their incredible search engine. - ![Browserstack](https://js.wiki/legacy/logo_browserstack.png) [Browserstack](https://www.browserstack.com/) for providing access to their great cross-browser testing tools. @@ -417,16 +486,22 @@ This project exists thanks to all the people who contribute. [[Contribute]](http [Cloudflare](https://www.cloudflare.com/) for providing their great CDN, SSL and advanced networking services. ![DigitalOcean](https://js.wiki/legacy/logo_digitalocean.png) -[DigitalOcean](https://m.do.co/c/5f7445bfa4d0) for providing hosting of the Wiki.js documentation site. +[DigitalOcean](https://m.do.co/c/5f7445bfa4d0) for providing hosting of the Wiki.js documentation site and APIs. ![Icons8](https://static.requarks.io/logo/icons8-text-h40.png) -[Icons8](https://icons8.com/) for providing beautiful icon sets. +[Icons8](https://icons8.com/) for providing access to their beautiful icon sets. + +![Localazy](https://static.requarks.io/logo/localazy-h40.png) +[Localazy](https://localazy.com/) for providing access to their great localization service. ![Lokalise](https://static.requarks.io/logo/lokalise-text-h40.png) [Lokalise](https://lokalise.com/) for providing access to their great localization tool. +![MacStadium](https://static.requarks.io/logo/macstadium-h40.png) +[MacStadium](https://www.macstadium.com) for providing access to their Mac hardware in the cloud. + ![Netlify](https://js.wiki/legacy/logo_netlify.png) -[Netlify](https://www.netlify.com) for providing hosting for landings and blog websites. +[Netlify](https://www.netlify.com) for providing hosting for our website. ![ngrok](https://static.requarks.io/logo/ngrok-h40.png) [ngrok](https://ngrok.com) for providing access to their great HTTP tunneling services. diff --git a/SECURITY.md b/SECURITY.md index 44cfc409..a68b8b9f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -13,11 +13,11 @@ If you find such vulnerability, it's important to disclose it in a quick and sec ## Reporting a Vulnerability -**DO NOT CREATE AN ISSUE ON GITHUB** to report a potential vulnerability / security problem. Instead, choose one of these options: +**DO NOT CREATE A GITHUB ISSUE / DISCUSSION** to report a potential vulnerability / security problem. Instead, choose one of these options: -### A) Disclose on Huntr.dev +### A) Submit a Vulnerability Report *(recommended)* -Disclose the vulnerability on [Huntr.dev](https://huntr.dev/bounties/disclose) for the repository `https://github.com/Requarks/wiki`. +Fill in the form on https://github.com/requarks/wiki/security/advisories/new ### B) Send an email diff --git a/client/components/admin.vue b/client/components/admin.vue index f6e3722a..1d0762f3 100644 --- a/client/components/admin.vue +++ b/client/components/admin.vue @@ -65,15 +65,6 @@ v-list-item(to='/comments') v-list-item-avatar(size='24', tile): v-icon mdi-comment-text-outline v-list-item-title {{ $t('admin:comments.title') }} - v-list-item(to='/editor', disabled) - v-list-item-avatar(size='24', tile): v-icon(color='grey lighten-2') mdi-playlist-edit - v-list-item-title {{ $t('admin:editor.title') }} - v-list-item(to='/extensions') - v-list-item-avatar(size='24', tile): v-icon mdi-chip - v-list-item-title {{ $t('admin:extensions.title') }} - v-list-item(to='/logging', disabled) - v-list-item-avatar(size='24', tile): v-icon(color='grey lighten-2') mdi-script-text-outline - v-list-item-title {{ $t('admin:logging.title') }} v-list-item(to='/rendering', color='primary') v-list-item-avatar(size='24', tile): v-icon mdi-cogs v-list-item-title {{ $t('admin:rendering.title') }} @@ -104,9 +95,6 @@ v-list-item(to='/utilities', color='primary', v-if='hasPermission(`manage:system`)') v-list-item-avatar(size='24', tile): v-icon mdi-wrench-outline v-list-item-title {{ $t('admin:utilities.title') }} - v-list-item(to='/webhooks', v-if='hasPermission(`manage:system`)', disabled) - v-list-item-avatar(size='24', tile): v-icon(color='grey lighten-2') mdi-webhook - v-list-item-title {{ $t('admin:webhooks.title') }} v-list-group( to='/dev' no-action diff --git a/client/components/admin/admin-contribute.vue b/client/components/admin/admin-contribute.vue index e13507fa..e3d85851 100644 --- a/client/components/admin/admin-contribute.vue +++ b/client/components/admin/admin-contribute.vue @@ -184,7 +184,7 @@ v-list-item-title Netlify v-list-item-subtitle Deploy modern static websites with Netlify. Get CDN, Continuous deployment, 1-click HTTPS, and all the services you need. v-list-item-action - v-btn(icon, href='https://wwwnetlify.com', target='_blank') + v-btn(icon, href='https://www.netlify.com', target='_blank') v-icon(color='grey') mdi-earth diff --git a/client/components/admin/admin-general.vue b/client/components/admin/admin-general.vue index 24829c8c..07596074 100644 --- a/client/components/admin/admin-general.vue +++ b/client/components/admin/admin-general.vue @@ -82,6 +82,15 @@ :return-object='false' :hint='$t(`admin:general.contentLicenseHint`)' persistent-hint + ) + v-text-field.mt-3( + outlined + :label='$t(`admin:general.footerOverride`)' + v-model='config.footerOverride' + prepend-icon='mdi-page-layout-footer' + append-icon='mdi-language-markdown' + persistent-hint + :hint='$t(`admin:general.footerOverrideHint`)' ) v-divider .overline.grey--text.pa-4 SEO @@ -144,7 +153,7 @@ //- ) //- v-divider.mt-3 - v-switch( + v-switch.mt-0( inset label='Comments' color='indigo' @@ -164,6 +173,89 @@ //- disabled //- ) + v-card.mt-5.animated.fadeInUp.wait-p6s + v-toolbar(color='primary', dark, dense, flat) + v-toolbar-title.subtitle-1 URL Handling + v-card-text + v-text-field( + outlined + :label='$t(`admin:general.pageExtensions`)' + v-model='config.pageExtensions' + prepend-icon='mdi-format-text-wrapping-overflow' + :hint='$t(`admin:general.pageExtensionsHint`)' + persistent-hint + ) + + v-card.mt-5.animated.fadeInUp.wait-p7s + v-toolbar(color='primary', dark, dense, flat) + v-toolbar-title.subtitle-1 {{$t('admin:general.editShortcuts')}} + v-card-text + v-switch.mt-0( + inset + :label='$t(`admin:general.editFab`)' + color='primary' + v-model='config.editFab' + persistent-hint + :hint='$t(`admin:general.editFabHint`)' + ) + v-divider + .overline.grey--text.pa-4 {{$t('admin:general.editMenuBar')}} + .px-3.pb-3 + v-switch.mt-0.ml-1( + inset + :label='$t(`admin:general.displayEditMenuBar`)' + color='primary' + v-model='config.editMenuBar' + persistent-hint + :hint='$t(`admin:general.displayEditMenuBarHint`)' + ) + v-switch.mt-4.ml-1( + v-if='config.editMenuBar' + inset + :label='$t(`admin:general.displayEditMenuBtn`)' + color='primary' + v-model='config.editMenuBtn' + persistent-hint + :hint='$t(`admin:general.displayEditMenuBtnHint`)' + ) + v-switch.mt-4.ml-1( + v-if='config.editMenuBar' + inset + :label='$t(`admin:general.displayEditMenuExternalBtn`)' + color='primary' + v-model='config.editMenuExternalBtn' + persistent-hint + :hint='$t(`admin:general.displayEditMenuExternalBtnHint`)' + ) + template(v-if='config.editMenuBar && config.editMenuExternalBtn') + v-divider + .overline.grey--text.pa-4 External Edit Button + .px-3.pb-3 + v-text-field( + outlined + :label='$t(`admin:general.editMenuExternalName`)' + v-model='config.editMenuExternalName' + prepend-icon='mdi-format-title' + :hint='$t(`admin:general.editMenuExternalNameHint`)' + persistent-hint + ) + v-text-field.mt-3( + outlined + :label='$t(`admin:general.editMenuExternalIcon`)' + v-model='config.editMenuExternalIcon' + prepend-icon='mdi-dice-5' + :hint='$t(`admin:general.editMenuExternalIconHint`)' + persistent-hint + ) + v-text-field.mt-3( + outlined + :label='$t(`admin:general.editMenuExternalUrl`)' + v-model='config.editMenuExternalUrl' + prepend-icon='mdi-near-me' + :hint='$t(`admin:general.editMenuExternalUrlHint`)' + persistent-hint + ) + component(:is='activeModal') @@ -197,12 +289,21 @@ export default { analyticsId: '', company: '', contentLicense: '', + footerOverride: '', logoUrl: '', featureAnalytics: false, featurePageRatings: false, featurePageComments: false, featurePersonalWikis: false, - featureTinyPNG: false + featureTinyPNG: false, + pageExtensions: '', + editFab: false, + editMenuBar: false, + editMenuBtn: false, + editMenuExternalBtn: false, + editMenuExternalName: '', + editMenuExternalIcon: '', + editMenuExternalUrl: '' }, metaRobots: [ { text: 'Index', value: 'index' }, @@ -217,6 +318,7 @@ export default { logoUrl: sync('site/logoUrl'), company: sync('site/company'), contentLicense: sync('site/contentLicense'), + footerOverride: sync('site/footerOverride'), activeModal: sync('editor/activeModal'), contentLicenses () { return [ @@ -247,33 +349,51 @@ export default { await this.$apollo.mutate({ mutation: gql` mutation ( - $host: String! - $title: String! - $description: String! - $robots: [String]! - $analyticsService: String! - $analyticsId: String! - $company: String! - $contentLicense: String! - $logoUrl: String! - $featurePageRatings: Boolean! - $featurePageComments: Boolean! - $featurePersonalWikis: Boolean! + $host: String + $title: String + $description: String + $robots: [String] + $analyticsService: String + $analyticsId: String + $company: String + $contentLicense: String + $footerOverride: String + $logoUrl: String + $pageExtensions: String + $featurePageRatings: Boolean + $featurePageComments: Boolean + $featurePersonalWikis: Boolean + $editFab: Boolean + $editMenuBar: Boolean + $editMenuBtn: Boolean + $editMenuExternalBtn: Boolean + $editMenuExternalName: String + $editMenuExternalIcon: String + $editMenuExternalUrl: String ) { site { updateConfig( - host: $host, - title: $title, - description: $description, - robots: $robots, - analyticsService: $analyticsService, - analyticsId: $analyticsId, - company: $company, - contentLicense: $contentLicense, - logoUrl: $logoUrl, - featurePageRatings: $featurePageRatings, - featurePageComments: $featurePageComments, + host: $host + title: $title + description: $description + robots: $robots + analyticsService: $analyticsService + analyticsId: $analyticsId + company: $company + contentLicense: $contentLicense + footerOverride: $footerOverride + logoUrl: $logoUrl + pageExtensions: $pageExtensions + featurePageRatings: $featurePageRatings + featurePageComments: $featurePageComments featurePersonalWikis: $featurePersonalWikis + editFab: $editFab + editMenuBar: $editMenuBar + editMenuBtn: $editMenuBtn + editMenuExternalBtn: $editMenuExternalBtn + editMenuExternalName: $editMenuExternalName + editMenuExternalIcon: $editMenuExternalIcon + editMenuExternalUrl: $editMenuExternalUrl ) { responseResult { succeeded @@ -294,10 +414,19 @@ export default { analyticsId: _.get(this.config, 'analyticsId', ''), company: _.get(this.config, 'company', ''), contentLicense: _.get(this.config, 'contentLicense', ''), + footerOverride: _.get(this.config, 'footerOverride', ''), logoUrl: _.get(this.config, 'logoUrl', ''), + pageExtensions: _.get(this.config, 'pageExtensions', ''), featurePageRatings: _.get(this.config, 'featurePageRatings', false), featurePageComments: _.get(this.config, 'featurePageComments', false), - featurePersonalWikis: _.get(this.config, 'featurePersonalWikis', false) + featurePersonalWikis: _.get(this.config, 'featurePersonalWikis', false), + editFab: _.get(this.config, 'editFab', false), + editMenuBar: _.get(this.config, 'editMenuBar', false), + editMenuBtn: _.get(this.config, 'editMenuBtn', false), + editMenuExternalBtn: _.get(this.config, 'editMenuExternalBtn', false), + editMenuExternalName: _.get(this.config, 'editMenuExternalName', ''), + editMenuExternalIcon: _.get(this.config, 'editMenuExternalIcon', ''), + editMenuExternalUrl: _.get(this.config, 'editMenuExternalUrl', '') }, watchLoading (isLoading) { this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-site-update') @@ -311,6 +440,7 @@ export default { this.siteTitle = this.config.title this.company = this.config.company this.contentLicense = this.config.contentLicense + this.footerOverride = this.config.footerOverride this.logoUrl = this.config.logoUrl } catch (err) { this.$store.commit('pushGraphError', err) @@ -346,10 +476,19 @@ export default { analyticsId company contentLicense + footerOverride logoUrl + pageExtensions featurePageRatings featurePageComments featurePersonalWikis + editFab + editMenuBar + editMenuBtn + editMenuExternalBtn + editMenuExternalName + editMenuExternalIcon + editMenuExternalUrl } } } diff --git a/client/components/admin/admin-groups-edit-rules.vue b/client/components/admin/admin-groups-edit-rules.vue index 89d97db4..f52d9265 100644 --- a/client/components/admin/admin-groups-edit-rules.vue +++ b/client/components/admin/admin-groups-edit-rules.vue @@ -214,8 +214,8 @@ export default { return { roles: [ { text: 'Read Pages', value: 'read:pages', icon: 'mdi-file-eye-outline' }, - { text: 'Create Pages', value: 'write:pages', icon: 'mdi-file-plus-outline' }, - { text: 'Edit + Move Pages', value: 'manage:pages', icon: 'mdi-file-document-edit-outline' }, + { text: 'Create + Edit Pages', value: 'write:pages', icon: 'mdi-file-plus-outline' }, + { text: 'Rename / Move Pages', value: 'manage:pages', icon: 'mdi-file-document-edit-outline' }, { text: 'Delete Pages', value: 'delete:pages', icon: 'mdi-file-remove-outline' }, { text: 'View Pages Source', value: 'read:source', icon: 'mdi-code-tags' }, { text: 'View Pages History', value: 'read:history', icon: 'mdi-history' }, diff --git a/client/components/admin/admin-mail.vue b/client/components/admin/admin-mail.vue index 660660f9..4db028af 100644 --- a/client/components/admin/admin-mail.vue +++ b/client/components/admin/admin-mail.vue @@ -57,6 +57,16 @@ :hint='$t(`admin:mail.smtpPortHint`)' style='max-width: 300px;' ) + v-text-field( + outlined + v-model='config.name' + :label='$t(`admin:mail.smtpName`)' + required + :counter='255' + prepend-icon='mdi-server' + persistent-hint + :hint='$t(`admin:mail.smtpNameHint`)' + ) v-switch( v-model='config.secure' :label='$t(`admin:mail.smtpTLS`)' @@ -169,6 +179,7 @@ export default { senderEmail: '', host: '', port: 0, + name: '', secure: false, verifySSL: false, user: '', @@ -192,6 +203,7 @@ export default { senderEmail: this.config.senderEmail || '', host: this.config.host || '', port: _.toSafeInteger(this.config.port) || 0, + name: this.config.name || '', secure: this.config.secure || false, verifySSL: this.config.verifySSL || false, user: this.config.user || '', diff --git a/client/components/admin/admin-pages-visualize.vue b/client/components/admin/admin-pages-visualize.vue index 116b38a9..3c9b20eb 100644 --- a/client/components/admin/admin-pages-visualize.vue +++ b/client/components/admin/admin-pages-visualize.vue @@ -104,7 +104,7 @@ export default { const truncatePath = path => _.take(path.split('/'), depth).join('/') const descendantsByChild = Object.entries(_.groupBy(descendants, page => truncatePath(page.path))) - .map(([childPath, descendantsGroup]) => [getPage(childPath), descendantsGroup]) + .map(([childPath, descendantsGroup]) => [getPage(childPath), _.sortBy(descendantsGroup, child => child.path)]) .map(([child, descendantsGroup]) => [child, _.filter(descendantsGroup, d => d.path !== child.path)]) return { diff --git a/client/components/admin/admin-security.vue b/client/components/admin/admin-security.vue index 7a8d305b..8c062c52 100644 --- a/client/components/admin/admin-security.vue +++ b/client/components/admin/admin-security.vue @@ -265,7 +265,7 @@ export default { securityOpenRedirect: true, securityIframe: true, securityReferrerPolicy: true, - securityTrustProxy: true, + securityTrustProxy: false, securitySRI: true, securityHSTS: false, securityHSTSDuration: 0, diff --git a/client/components/admin/admin-theme.vue b/client/components/admin/admin-theme.vue index b3aed1a1..eb357c6c 100644 --- a/client/components/admin/admin-theme.vue +++ b/client/components/admin/admin-theme.vue @@ -55,15 +55,24 @@ v-toolbar(color='primary', dark, dense, flat) v-toolbar-title.subtitle-1 {{$t(`admin:theme.options`)}} v-card-text + v-select( + :items='tocPositions' + outlined + prepend-icon='mdi-border-vertical' + v-model='config.tocPosition' + label='Table of Contents Position' + persistent-hint + hint='Select whether the table of contents is shown on the left, right or not at all.' + ) v-range-slider( prepend-icon='mdi-menu-open' - :label='$t(`admin:theme.tocHeadingLevels`)' + label='Heading Levels in ToC' v-model='tocRange' :min='1' :max='6' :tick-labels='["H1", "H2", "H3", "H4", "H5", "H6"]' + hint='Select which levels of the toc are displayed.' ) - .text-caption {{$t('admin:theme.tocHeadingLevelsHint')}} v-flex(lg6 xs12) v-card.animated.fadeInUp.wait-p2s @@ -129,6 +138,7 @@ export default { max: 2 }, iconset: '', + tocPosition: 'left', injectCSS: '', injectHead: '', injectBody: '' @@ -170,6 +180,13 @@ export default { width: 100 } ] + }, + tocPositions () { + return [ + { text: 'Left (default)', value: 'left' }, + { text: 'Right', value: 'right' }, + { text: 'Hidden', value: 'off' } + ] } }, watch: { @@ -196,6 +213,7 @@ export default { iconset: this.config.iconset, darkMode: this.darkMode, tocDepth: this.config.tocDepth, + tocPosition: this.config.tocPosition, injectCSS: this.config.injectCSS, injectHead: this.config.injectHead, injectBody: this.config.injectBody diff --git a/client/components/admin/admin-users-edit.vue b/client/components/admin/admin-users-edit.vue index 7b5acae6..a9e20070 100644 --- a/client/components/admin/admin-users-edit.vue +++ b/client/components/admin/admin-users-edit.vue @@ -499,9 +499,9 @@ export default { { text: '(GMT-03:00) Rothera', value: 'Antarctica/Rothera' }, { text: '(GMT-03:00) Salvador', value: 'America/Bahia' }, { text: '(GMT-03:00) Santiago', value: 'America/Santiago' }, + { text: '(GMT-03:00) Sao Paulo', value: 'America/Sao_Paulo' }, { text: '(GMT-03:00) Stanley', value: 'Atlantic/Stanley' }, { text: '(GMT-02:00) Noronha', value: 'America/Noronha' }, - { text: '(GMT-02:00) Sao Paulo', value: 'America/Sao_Paulo' }, { text: '(GMT-02:00) South Georgia', value: 'Atlantic/South_Georgia' }, { text: '(GMT-01:00) Azores', value: 'Atlantic/Azores' }, { text: '(GMT-01:00) Cape Verde', value: 'Atlantic/Cape_Verde' }, diff --git a/client/components/common/search-results.vue b/client/components/common/search-results.vue index 64c57f41..ddc33208 100644 --- a/client/components/common/search-results.vue +++ b/client/components/common/search-results.vue @@ -105,6 +105,9 @@ export default { } else { this.searchIsLoading = true } + }, + results() { + this.cursor = 0 } }, mounted() { @@ -153,6 +156,9 @@ export default { skip() { return !this.search || this.search.length < 2 }, + result() { + this.pagination = 1 + }, update: (data) => _.get(data, 'pages.search', {}), watchLoading (isLoading) { this.searchIsLoading = isLoading diff --git a/client/components/editor.vue b/client/components/editor.vue index 530c99fb..8ccb5d42 100644 --- a/client/components/editor.vue +++ b/client/components/editor.vue @@ -77,6 +77,7 @@ export default { editorApi: () => import(/* webpackChunkName: "editor-api", webpackMode: "lazy" */ './editor/editor-api.vue'), editorCode: () => import(/* webpackChunkName: "editor-code", webpackMode: "lazy" */ './editor/editor-code.vue'), editorCkeditor: () => import(/* webpackChunkName: "editor-ckeditor", webpackMode: "lazy" */ './editor/editor-ckeditor.vue'), + editorAsciidoc: () => import(/* webpackChunkName: "editor-asciidoc", webpackMode: "lazy" */ './editor/editor-asciidoc.vue'), editorMarkdown: () => import(/* webpackChunkName: "editor-markdown", webpackMode: "lazy" */ './editor/editor-markdown.vue'), editorRedirect: () => import(/* webpackChunkName: "editor-redirect", webpackMode: "lazy" */ './editor/editor-redirect.vue'), editorModalEditorselect: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-editorselect.vue'), diff --git a/client/components/editor/markdown/fold.js b/client/components/editor/common/cmFold.js similarity index 92% rename from client/components/editor/markdown/fold.js rename to client/components/editor/common/cmFold.js index 1bc56ef5..52267303 100644 --- a/client/components/editor/markdown/fold.js +++ b/client/components/editor/common/cmFold.js @@ -7,7 +7,13 @@ const maxDepth = 100 const codeBlockStartMatch = /^`{3}[a-zA-Z0-9]+$/ const codeBlockEndMatch = /^`{3}$/ -CodeMirror.registerHelper('fold', 'markdown', function (cm, start) { +export default { + register(lang) { + CodeMirror.registerHelper('fold', lang, foldHandler) + } +} + +function foldHandler (cm, start) { const firstLine = cm.getLine(start.line) const lastLineNo = cm.lastLine() let end @@ -59,4 +65,4 @@ CodeMirror.registerHelper('fold', 'markdown', function (cm, start) { from: CodeMirror.Pos(start.line, firstLine.length), to: CodeMirror.Pos(end, cm.getLine(end).length) } -}) +} diff --git a/client/components/editor/editor-asciidoc.vue b/client/components/editor/editor-asciidoc.vue new file mode 100644 index 00000000..296b2414 --- /dev/null +++ b/client/components/editor/editor-asciidoc.vue @@ -0,0 +1,707 @@ + + + + + diff --git a/client/components/editor/editor-markdown.vue b/client/components/editor/editor-markdown.vue index 6134524d..4ca6e192 100644 --- a/client/components/editor/editor-markdown.vue +++ b/client/components/editor/editor-markdown.vue @@ -124,44 +124,19 @@ span {{$t('editor:markup.insertAssets')}} v-tooltip(right, color='teal') template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p2s(icon, tile, v-on='on', dark, disabled, @click='toggleModal(`editorModalBlocks`)').mx-0 - v-icon(:color='activeModal === `editorModalBlocks` ? `teal` : ``') mdi-view-dashboard-outline - span {{$t('editor:markup.insertBlock')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p3s(icon, tile, v-on='on', dark, disabled).mx-0 - v-icon mdi-code-braces - span {{$t('editor:markup.insertCodeBlock')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p4s(icon, tile, v-on='on', dark, disabled).mx-0 - v-icon mdi-movie - span {{$t('editor:markup.insertVideoAudio')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p5s(icon, tile, v-on='on', dark, @click='toggleModal(`editorModalDrawio`)').mx-0 + v-btn.mt-3.animated.fadeInLeft.wait-p2s(icon, tile, v-on='on', dark, @click='toggleModal(`editorModalDrawio`)').mx-0 v-icon mdi-chart-multiline span {{$t('editor:markup.insertDiagram')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p6s(icon, tile, v-on='on', dark, disabled).mx-0 - v-icon mdi-function-variant - span {{$t('editor:markup.insertMathExpression')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p7s(icon, tile, v-on='on', dark, disabled).mx-0 - v-icon mdi-table-plus - span {{$t('editor:markup.tableHelper')}} template(v-if='$vuetify.breakpoint.mdAndUp') v-spacer v-tooltip(right, color='teal') template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p8s(icon, tile, v-on='on', dark, @click='toggleFullscreen').mx-0 + v-btn.mt-3.animated.fadeInLeft.wait-p3s(icon, tile, v-on='on', dark, @click='toggleFullscreen').mx-0 v-icon mdi-arrow-expand-all span {{$t('editor:markup.distractionFreeMode')}} v-tooltip(right, color='teal') template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p9s(icon, tile, v-on='on', dark, @click='toggleHelp').mx-0 + v-btn.mt-3.animated.fadeInLeft.wait-p4s(icon, tile, v-on='on', dark, @click='toggleHelp').mx-0 v-icon(:color='helpShown ? `teal` : ``') mdi-help-circle span {{$t('editor:markup.markdownFormattingHelp')}} .editor-markdown-editor @@ -220,12 +195,12 @@ import 'codemirror/addon/hint/show-hint.js' import 'codemirror/addon/fold/foldcode.js' import 'codemirror/addon/fold/foldgutter.js' import 'codemirror/addon/fold/foldgutter.css' -import './markdown/fold' // Markdown-it import MarkdownIt from 'markdown-it' import mdAttrs from 'markdown-it-attrs' -import mdEmoji from 'markdown-it-emoji' +import mdDecorate from 'markdown-it-decorate' +import { full as mdEmoji } from 'markdown-it-emoji' import mdTaskLists from 'markdown-it-task-lists' import mdExpandTabs from 'markdown-it-expand-tabs' import mdAbbr from 'markdown-it-abbr' @@ -250,6 +225,7 @@ import mermaid from 'mermaid' // Helpers import katexHelper from './common/katex' import tabsetHelper from './markdown/tabset' +import cmFold from './common/cmFold' // ======================================== // INIT @@ -288,6 +264,7 @@ const md = new MarkdownIt({ .use(mdAttrs, { allowedAttributes: ['id', 'class', 'target'] }) + .use(mdDecorate) .use(underline) .use(mdEmoji) .use(mdTaskLists, { label: false, labelAfter: false }) @@ -335,6 +312,7 @@ md.renderer.rules.paragraph_open = injectLineNumbers md.renderer.rules.heading_open = injectLineNumbers md.renderer.rules.blockquote_open = injectLineNumbers +cmFold.register('markdown') // ======================================== // PLANTUML // ======================================== @@ -346,11 +324,12 @@ plantuml.init(md, {}) // KATEX // ======================================== +const macros = {} md.inline.ruler.after('escape', 'katex_inline', katexHelper.katexInline) md.renderer.rules.katex_inline = (tokens, idx) => { try { return katex.renderToString(tokens[idx].content, { - displayMode: false + displayMode: false, macros }) } catch (err) { console.warn(err) @@ -363,7 +342,7 @@ md.block.ruler.after('blockquote', 'katex_block', katexHelper.katexBlock, { md.renderer.rules.katex_block = (tokens, idx) => { try { return `

` + katex.renderToString(tokens[idx].content, { - displayMode: true + displayMode: true, macros }) + `

` } catch (err) { console.warn(err) diff --git a/client/components/editor/editor-modal-editorselect.vue b/client/components/editor/editor-modal-editorselect.vue index b5ce35f5..df2adf96 100644 --- a/client/components/editor/editor-modal-editorselect.vue +++ b/client/components/editor/editor-modal-editorselect.vue @@ -6,57 +6,7 @@ .subtitle-1.white--text {{$t('editor:select.title')}} v-container(grid-list-lg, fluid) v-layout(row, wrap, justify-center) - v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.primary.animated.fadeInUp( - hover - light - ripple - ) - v-card-text.text-center(@click='') - img(src='/_assets/svg/editor-icon-api.svg', alt='API', style='width: 36px; opacity: .5;') - .body-2.blue--text.mt-2.text--lighten-2 API Docs - .caption.blue--text.text--lighten-1 REST / GraphQL - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='primary' - opacity='.8' - ) - .body-2.mt-7 Coming Soon - v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.primary.animated.fadeInUp.wait-p1s( - hover - light - ripple - ) - v-card-text.text-center(@click='') - img(src='/_assets/svg/editor-icon-wikitext.svg', alt='WikiText', style='width: 36px; opacity: .5;') - .body-2.blue--text.mt-2.text--lighten-2 Blog - .caption.blue--text.text--lighten-1 Timeline of Posts - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='primary' - opacity='.8' - ) - .body-2.mt-7 Coming Soon - v-flex(xs4) - v-card.radius-7.animated.fadeInUp.wait-p2s( - hover - light - ripple - ) - v-card-text.text-center(@click='selectEditor("code")') - img(src='/_assets/svg/editor-icon-code.svg', alt='Code', style='width: 36px;') - .body-2.primary--text.mt-2 Code - .caption.grey--text Raw HTML - v-flex(xs4) + v-flex(xs6) v-card.radius-7.animated.fadeInUp.wait-p1s( hover light @@ -66,28 +16,8 @@ img(src='/_assets/svg/editor-icon-markdown.svg', alt='Markdown', style='width: 36px;') .body-2.primary--text.mt-2 Markdown .caption.grey--text Plain Text Formatting - v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.primary.animated.fadeInUp.wait-p2s( - hover - light - ripple - ) - v-card-text.text-center(@click='') - img(src='/_assets/svg/editor-icon-tabular.svg', alt='Tabular', style='width: 36px; opacity: .5;') - .body-2.blue--text.mt-2.text--lighten-2 Tabular - .caption.blue--text.text--lighten-1 Excel-like - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='primary' - opacity='.8' - ) - .body-2.mt-7 Coming Soon - v-flex(xs4) - v-card.radius-7.animated.fadeInUp.wait-p3s( + v-flex(xs6) + v-card.radius-7.animated.fadeInUp.wait-p2s( hover light ripple @@ -96,85 +26,36 @@ img(src='/_assets/svg/editor-icon-ckeditor.svg', alt='Visual Editor', style='width: 36px;') .body-2.mt-2.primary--text Visual Editor .caption.grey--text Rich-text WYSIWYG - //- .caption.blue--text.text--lighten-2 {{$t('editor:select.cannotChange')}} - - v-card.radius-7.mt-2(color='teal darken-3', dark) - v-card-text.text-center.py-4 - .subtitle-1.white--text {{$t('editor:select.customView')}} - v-container(grid-list-lg, fluid) - v-layout(row, wrap, justify-center) v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.animated.fadeInUp( - hover - light - ripple - ) - v-card-text.text-center(@click='fromTemplate') - img(src='/_assets/svg/icon-cube.svg', alt='From Template', style='width: 42px; opacity: .5;') - .body-2.mt-1.teal--text From Template - .caption.grey--text Use an existing page... + v-card.radius-7.animated.fadeInUp.wait-p3s( + hover + light + ripple + ) + v-card-text.text-center(@click='selectEditor("asciidoc")') + img(src='/_assets/svg/editor-icon-asciidoc.svg', alt='AsciiDoc', style='width: 36px;') + .body-2.primary--text.mt-2 AsciiDoc + .caption.grey--text Plain Text Formatting v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.teal.animated.fadeInUp.wait-p1s( - hover - light - ripple - ) - //- v-card-text.text-center(@click='selectEditor("redirect")') - v-card-text.text-center(@click='') - img(src='/_assets/svg/icon-route.svg', alt='Redirection', style='width: 42px; opacity: .5;') - .body-2.mt-1.teal--text.text--lighten-2 Redirection - .caption.teal--text.text--lighten-1 Redirect the user to... + v-card.radius-7.animated.fadeInUp.wait-p4s( + hover + light + ripple + ) + v-card-text.text-center(@click='selectEditor("code")') + img(src='/_assets/svg/editor-icon-code.svg', alt='Code', style='width: 36px;') + .body-2.primary--text.mt-2 Code + .caption.grey--text Raw HTML v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.teal.animated.fadeInUp.wait-p2s( - hover - light - ripple - ) - v-card-text.text-center(@click='') - img(src='/_assets/svg/icon-sewing-patch.svg', alt='Code', style='width: 42px; opacity: .5;') - .body-2.mt-1.teal--text.text--lighten-2 Embed - .caption.teal--text.text--lighten-1 Include external pages - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='teal' - opacity='.8' - ) - .body-2.mt-7 Coming Soon - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.mt-2(color='indigo darken-3', dark) - v-toolbar(dense, flat, color='light-green darken-3') - v-spacer - .caption.mr-1 or convert from - v-btn.mx-1.animated.fadeInUp(depressed, color='light-green darken-2', @click='', disabled) - v-icon(left) mdi-alpha-a-circle - .body-2.text-none AsciiDoc - v-btn.mx-1.animated.fadeInUp.wait-p1s(depressed, color='light-green darken-2', @click='', disabled) - v-icon(left) mdi-alpha-c-circle - .body-2.text-none CREOLE - v-btn.mx-1.animated.fadeInUp.wait-p2s(depressed, color='light-green darken-2', @click='', disabled) - v-icon(left) mdi-alpha-t-circle - .body-2.text-none Textile - v-btn.mx-1.animated.fadeInUp.wait-p3s(depressed, color='light-green darken-2', @click='', disabled) - v-icon(left) mdi-alpha-w-circle - .body-2.text-none WikiText - v-spacer - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='light-green darken-3' - opacity='.8' - ) - .body-2 Coming Soon + v-card.radius-7.animated.fadeInUp.wait-p5s( + hover + light + ripple + ) + v-card-text.text-center(@click='fromTemplate') + img(src='/_assets/svg/icon-cube.svg', alt='From Template', style='width: 42px; opacity: .5;') + .body-2.mt-1.teal--text From Template + .caption.grey--text Use an existing page... page-selector(mode='select', v-model='templateDialogIsShown', :open-handler='fromTemplateHandle', :path='path', :locale='locale', must-exist) diff --git a/client/components/editor/editor-modal-properties.vue b/client/components/editor/editor-modal-properties.vue index 79a32e6c..dc885aa1 100644 --- a/client/components/editor/editor-modal-properties.vue +++ b/client/components/editor/editor-modal-properties.vue @@ -92,7 +92,7 @@ v-dialog( ) v-tab-item(transition='fade-transition', reverse-transition='fade-transition') v-card-text - .overline {{$t('editor:props.tocTitle')}} + .overline.pb-5 {{$t('editor:props.tocTitle')}} v-switch( :label='$t(`editor:props.tocUseDefault`)' v-model='useDefaultTocDepth' diff --git a/client/components/profile/profile.vue b/client/components/profile/profile.vue index 918cb6d3..345476d2 100644 --- a/client/components/profile/profile.vue +++ b/client/components/profile/profile.vue @@ -469,9 +469,9 @@ export default { { text: '(GMT-03:00) Rothera', value: 'Antarctica/Rothera' }, { text: '(GMT-03:00) Salvador', value: 'America/Bahia' }, { text: '(GMT-03:00) Santiago', value: 'America/Santiago' }, + { text: '(GMT-03:00) Sao Paulo', value: 'America/Sao_Paulo' }, { text: '(GMT-03:00) Stanley', value: 'Atlantic/Stanley' }, { text: '(GMT-02:00) Noronha', value: 'America/Noronha' }, - { text: '(GMT-02:00) Sao Paulo', value: 'America/Sao_Paulo' }, { text: '(GMT-02:00) South Georgia', value: 'Atlantic/South_Georgia' }, { text: '(GMT-01:00) Azores', value: 'Atlantic/Azores' }, { text: '(GMT-01:00) Cape Verde', value: 'Atlantic/Cape_Verde' }, diff --git a/client/components/source.vue b/client/components/source.vue index 6da6906a..2e6b8baa 100644 --- a/client/components/source.vue +++ b/client/components/source.vue @@ -20,8 +20,7 @@ v-card.grey.radius-7(flat, :class='$vuetify.theme.dark ? `darken-4` : `lighten-4`') v-card-text pre - code - slot + slot nav-footer notify diff --git a/client/components/tags.vue b/client/components/tags.vue index 3d717b38..56bc6cbb 100644 --- a/client/components/tags.vue +++ b/client/components/tags.vue @@ -98,6 +98,7 @@ :search='innerSearch' :loading='isLoading' :options.sync='pagination' + @page-count='pageTotal = $event' hide-default-footer ref='dude' ) @@ -183,6 +184,7 @@ export default { sortDesc: [false] }, pages: [], + pageTotal: 0, isLoading: true, scrollStyle: { vuescroll: {}, @@ -214,9 +216,6 @@ export default { tagsSelected () { return _.filter(this.tags, t => _.includes(this.selection, t.tag)) }, - pageTotal () { - return Math.ceil(this.pages.length / this.pagination.itemsPerPage) - }, orderByItems () { return [ { text: this.$t('tags:orderByField.creationDate'), value: 'createdAt' }, diff --git a/client/graph/admin/mail/mail-mutation-save-config.gql b/client/graph/admin/mail/mail-mutation-save-config.gql index 3b8f6999..611a1c0a 100644 --- a/client/graph/admin/mail/mail-mutation-save-config.gql +++ b/client/graph/admin/mail/mail-mutation-save-config.gql @@ -1,30 +1,32 @@ mutation ( - $senderName: String!, - $senderEmail: String!, - $host: String!, - $port: Int!, - $secure: Boolean!, - $verifySSL: Boolean!, - $user: String!, - $pass: String!, - $useDKIM: Boolean!, - $dkimDomainName: String!, - $dkimKeySelector: String!, + $senderName: String! + $senderEmail: String! + $host: String! + $port: Int! + $name: String! + $secure: Boolean! + $verifySSL: Boolean! + $user: String! + $pass: String! + $useDKIM: Boolean! + $dkimDomainName: String! + $dkimKeySelector: String! $dkimPrivateKey: String! ) { mail { updateConfig( - senderName: $senderName, - senderEmail: $senderEmail, - host: $host, - port: $port, - secure: $secure, - verifySSL: $verifySSL, - user: $user, - pass: $pass, - useDKIM: $useDKIM, - dkimDomainName: $dkimDomainName, - dkimKeySelector: $dkimKeySelector, + senderName: $senderName + senderEmail: $senderEmail + host: $host + port: $port + name: $name + secure: $secure + verifySSL: $verifySSL + user: $user + pass: $pass + useDKIM: $useDKIM + dkimDomainName: $dkimDomainName + dkimKeySelector: $dkimKeySelector dkimPrivateKey: $dkimPrivateKey ) { responseResult { diff --git a/client/graph/admin/mail/mail-query-config.gql b/client/graph/admin/mail/mail-query-config.gql index 66232acb..5d7091aa 100644 --- a/client/graph/admin/mail/mail-query-config.gql +++ b/client/graph/admin/mail/mail-query-config.gql @@ -5,6 +5,7 @@ senderEmail host port + name secure verifySSL user diff --git a/client/graph/admin/theme/theme-mutation-save.gql b/client/graph/admin/theme/theme-mutation-save.gql index ba4e4347..ed1d5343 100644 --- a/client/graph/admin/theme/theme-mutation-save.gql +++ b/client/graph/admin/theme/theme-mutation-save.gql @@ -1,22 +1,6 @@ -mutation( - $theme: String! - $iconset: String! - $darkMode: Boolean! - $tocDepth: RangeInput! - $injectCSS: String - $injectHead: String - $injectBody: String - ) { +mutation($theme: String!, $iconset: String!, $darkMode: Boolean!, $tocPosition: String, $tocDepth: RangeInput!, $injectCSS: String, $injectHead: String, $injectBody: String) { theming { - setConfig( - theme: $theme - iconset: $iconset - darkMode: $darkMode - tocDepth: $tocDepth - injectCSS: $injectCSS - injectHead: $injectHead - injectBody: $injectBody - ) { + setConfig(theme: $theme, iconset: $iconset, darkMode: $darkMode, tocPosition: $tocPosition, tocDepth: $tocDepth, injectCSS: $injectCSS, injectHead: $injectHead, injectBody: $injectBody) { responseResult { succeeded errorCode diff --git a/client/graph/admin/theme/theme-query-config.gql b/client/graph/admin/theme/theme-query-config.gql index 48a8ead1..9d9192b9 100644 --- a/client/graph/admin/theme/theme-query-config.gql +++ b/client/graph/admin/theme/theme-query-config.gql @@ -8,6 +8,7 @@ query { min max } + tocPosition injectCSS injectHead injectBody diff --git a/client/scss/base/base.scss b/client/scss/base/base.scss index f06afeea..03224354 100644 --- a/client/scss/base/base.scss +++ b/client/scss/base/base.scss @@ -30,6 +30,12 @@ html { } } +@media only screen and (min-width:960px) { + .v-application .v-footer { + padding-left: 272px + } +} + #root .v-application { .overline { line-height: 1rem; diff --git a/client/static/svg/editor-icon-asciidoc.svg b/client/static/svg/editor-icon-asciidoc.svg new file mode 100644 index 00000000..d0c954b1 --- /dev/null +++ b/client/static/svg/editor-icon-asciidoc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/store/page.js b/client/store/page.js index c187c58e..4eea9fca 100644 --- a/client/store/page.js +++ b/client/store/page.js @@ -46,7 +46,16 @@ const state = { manage: false } }, - commentsCount: 0 + commentsCount: 0, + editShortcuts: { + editFab: false, + editMenuBar: false, + editMenuBtn: false, + editMenuExternalBtn: false, + editMenuExternalName: '', + editMenuExternalIcon: '', + editMenuExternalUrl: '' + } } export default { diff --git a/client/store/site.js b/client/store/site.js index e26830e3..0e3369de 100644 --- a/client/store/site.js +++ b/client/store/site.js @@ -5,7 +5,9 @@ import { make } from 'vuex-pathify' const state = { company: siteConfig.company, contentLicense: siteConfig.contentLicense, + footerOverride: siteConfig.footerOverride, dark: siteConfig.darkMode, + tocPosition: siteConfig.tocPosition, mascot: true, title: siteConfig.title, logoUrl: siteConfig.logoUrl, diff --git a/client/themes/default/components/nav-footer.vue b/client/themes/default/components/nav-footer.vue index 08e44fcd..93368daa 100644 --- a/client/themes/default/components/nav-footer.vue +++ b/client/themes/default/components/nav-footer.vue @@ -1,7 +1,9 @@