diff --git a/README.md b/README.md index 6a670571..0afe4f56 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,8 @@ 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) [![Standard - JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-green.svg?style=flat&logo=javascript&logoColor=white)](http://standardjs.com/) -[![Downloads](https://img.shields.io/github/downloads/Requarks/wiki/total.svg?style=flat&logo=github)](https://github.com/Requarks/wiki/releases) -[![Docker Pulls](https://img.shields.io/docker/pulls/requarks/wiki.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/requarks/wiki/) -[![Build + Publish](https://github.com/Requarks/wiki/actions/workflows/build.yml/badge.svg)](https://github.com/Requarks/wiki/actions/workflows/build.yml) -[![Huntr](https://img.shields.io/badge/security%20bounty-disclose-brightgreen.svg?style=flat&logo=cachet&logoColor=white)](https://huntr.dev/bounties/disclose) [![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) @@ -16,412 +11,135 @@ [![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 +##### Next Generation Open Source Wiki -- **[Official Website](https://js.wiki/)** -- **[Documentation](https://docs.requarks.io/)** -- [Requirements](https://docs.requarks.io/install/requirements) -- [Installation](https://docs.requarks.io/install) -- [Demo](https://docs.requarks.io/demo) -- [Changelog](https://docs.requarks.io/releases) -- [Feature Requests](https://feedback.js.wiki/wiki) -- [Chat with us on Slack](https://wiki.requarks.io/slack) -- [Translations](https://docs.requarks.io/dev/translations) *(We need your help!)* -- [E2E Testing Results](https://dashboard.cypress.io/projects/r7qxah/runs) -- [Special Thanks](#special-thanks) -- [Contribute](#contributors) +- **[Official Website](https://next.js.wiki/)** +- **[Documentation](https://next.js.wiki/docs/)** -[Follow our Twitter feed](https://twitter.com/requarks) to learn about upcoming updates and new releases! +:warning: :warning: **THIS IS A VERY BUGGY, INCOMPLETE AND NON-SECURE DEVELOPMENT BRANCH! USE AT YOUR OWN RISK! THERE'S NO UPGRADE PATH FROM THIS BUILD.** :warning: :warning: -

Donate

+The current stable release (2.x) is available at https://js.wiki -
+--- -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`). - - [![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) - [![Donate on OpenCollective](https://img.shields.io/badge/donate-open%20collective-blue.svg?style=popout&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNTZweCIgaGVpZ2h0PSIyNTZweCIgdmlld0JveD0iMCAwIDI1NiAyNTYiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPjxnPjxwYXRoIGQ9Ik0yMDkuNzY1MTQ0LDEyOC4xNDk5NzkgQzIwOS43NjUxNDQsMTQ0LjE2MzMgMjA0Ljg2NDM4MSwxNTkuNDg5ODkgMTk2LjQ5ODc0NywxNzIuNzI1MDcyIEwyMjkuOTQ1Njc1LDIwNi4xNzE5OTkgQzI0Ni42ODIxMDUsMTgzLjg1Njc1OSAyNTUuNzI5MzA3LDE1Ni43MTUxNTIgMjU1LjcyOTMwNywxMjguODIxMTAyIEMyNTUuNzI5MzA3LDk5LjU1Njk5MTcgMjQ1Ljk3NDYwMyw3My4wNzEwMjA3IDIyOS4yNTg5NDQsNTEuNDg1ODEyOCBMMTk2LjQ4MzE0LDg0LjIxNDc5NCBDMjA1LjEyMjU2MSw5Ny4yMjI0NjgzIDIwOS43MzY5MDcsMTEyLjQ4NzgxIDIwOS43NDk1MzcsMTI4LjEwMzE1NiBMMjA5Ljc2NTE0NCwxMjguMTQ5OTc5IFoiIGZpbGw9IiNCOEQzRjQiPjwvcGF0aD48cGF0aCBkPSJNMTI3LjUxMzQ4NCwyMTAuMzU0ODE2IEM4Mi4xNDYwODcyLDIxMC4yNjg5NTggNDUuMzg3NTA5NCwxNzMuNTE3MzU4IDQ1LjI5MzAzOTMsMTI4LjE0OTk3OSBDNDUuMzYxNzUwMiw4Mi43NjQzMTM4IDgyLjEyNzg0ODcsNDUuOTg0MjU3IDEyNy41MTM0ODQsNDUuODk4MzE4NiBDMTQ0LjI0NDc1Miw0NS44OTgzMTg2IDE1OS41NzEzNDIsNTAuNzk5MDgxNyAxNzIuMTE5NzkyLDU5LjE2NDcxNTQgTDIwNC44NjQzODEsMjYuMzg4OTExNiBDMTgyLjU0MzY1LDkuNjY2NjUxMjkgMTU1LjQwMzQyOSwwLjYzMDg2MzI5OCAxMjcuNTEzNDg0LDAuNjM2NDk0NDAzIEM1Ny4xMjM1NDM3LDAuNjM2NDk0NDAzIDAsNTcuNzYwMDM4MSAwLDEyOC4xNDk5NzkgQzAsMTk4LjUwODcwNCA1Ny4xMjM1NDM3LDI1NS42NjM0NjMgMTI3LjUxMzQ4NCwyNTUuNjYzNDYzIEMxNTUuNTM3MzUyLDI1NS43NDA4NzYgMTgyLjc3NTk4OSwyNDYuNDA4NTEgMjA0Ljg2NDM4MSwyMjkuMTYxODg0IEwxNzEuNDE3NDU0LDE5NS43MzA1NjQgQzE1OS41NTU3MzQsMjA1LjQ4NTI2OCAxNDQuMjYwMzU5LDIxMC4zNTQ4MTYgMTI3LjUxMzQ4NCwyMTAuMzU0ODE2IEwxMjcuNTEzNDg0LDIxMC4zNTQ4MTYgWiIgZmlsbD0iIzdGQURGMiI+PC9wYXRoPjwvZz48L3N2Zz4=)](https://opencollective.com/wikijs) - [![Donate via Paypal](https://img.shields.io/badge/donate-paypal-blue.svg?style=popout&logo=paypal)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FLV5X255Z9CJU&source=url) - [![Donate via Ethereum](https://img.shields.io/badge/donate-ethereum-999.svg?style=popout&logo=ethereum&logoColor=CCC)](https://etherscan.io/address/0xe1d55c19ae86f6bcbfb17e7f06ace96bdbb22cb5) - [![Donate via Bitcoin](https://img.shields.io/badge/donate-bitcoin-ff9900.svg?style=popout&logo=bitcoin&logoColor=CCC)](https://checkout.opennode.com/p/2553c612-f863-4407-82b3-1a7685268747) - [![Buy a T-Shirt](https://img.shields.io/badge/buy-t--shirts-teal.svg?style=popout&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjBweCIgeT0iMHB4Igp3aWR0aD0iMjQiIGhlaWdodD0iMjQiCnZpZXdCb3g9IjAgMCAxOTIgMTkyIgpzdHlsZT0iIGZpbGw6IzAwMDAwMDsiPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIGZvbnQtZmFtaWx5PSJub25lIiBmb250LXdlaWdodD0ibm9uZSIgZm9udC1zaXplPSJub25lIiB0ZXh0LWFuY2hvcj0ibm9uZSIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0wLDE5MnYtMTkyaDE5MnYxOTJ6IiBmaWxsPSJub25lIj48L3BhdGg+PGcgZmlsbD0iIzFhYmM5YyI+PGcgaWQ9InN1cmZhY2UxIj48cGF0aCBkPSJNOTYsMGMtMTUuMjE4NzUsMCAtMjQuNjg3NSwzLjY1NjI1IC0yNS41LDRsLTIyLjUsNy4yNWMtMTAuNDA2MjUsMy4xODc1IC0xOS4wOTM3NSw5LjQzNzUgLTI1LjUsMTguMjVsLTIyLjUsNDIuNWwyNy4yNSwxNi43NWwxMi43NSwtMjR2MTE5LjI1YzAsNC40MDYyNSAyNS4wNjI1LDggNTYsOGMzMC45Mzc1LDAgNTYsLTMuNTkzNzUgNTYsLTh2LTExOS4yNWwxMi43NSwyNGwyNy4yNSwtMTYuNzVsLTIyLjUsLTQyLjVjLTYuNDA2MjUsLTguODEyNSAtMTUuMTU2MjUsLTE1LjA2MjUgLTI0Ljc1LC0xOC4yNWwtMjIuMjUsLTcuMjVjLTAuMTg3NSwwIC0xLjAzMTI1LDEuMzEyNSAtMiwyLjc1bDEuMjUsLTIuNWMwLDAgLTkuODQzNzUsLTQuMjUgLTI1Ljc1LC00LjI1ek05Niw4YzExLjQwNjI1LDAgMTguNDM3NSwyLjI1IDIxLDMuMjVjLTQuNDY4NzUsNS43NSAtMTEuNDA2MjUsMTIuNzUgLTIxLDEyLjc1Yy05LjQwNjI1LDAgLTE2LjQwNjI1LC03LjA2MjUgLTIwLjc1LC0xMi43NWMyLjg3NSwtMS4wNjI1IDkuODc1LC0zLjI1IDIwLjc1LC0zLjI1eiI+PC9wYXRoPjwvZz48L2c+PC9nPjwvc3ZnPg==)](https://wikijs.threadless.com) +## Requirements -
+- Node.js **18.x** or later +- Yarn +- PostgreSQL **11** or later -

Gold Tier Sponsors

+## Setup -
- - - - - - -
- - - -
-
+1. Clone the project +1. Make a copy of `config.sample.yml` and rename it to `config.yml` +1. Edit `config.yml` and fill in the database details. **You need an empty PostgreSQL database.** +1. Run the following commands to install dependencies and generate the client assets: + ```sh + yarn + yarn legacy:build + cd ux + yarn + yarn build + cd .. + ``` +1. Run this command to start the server: + ```sh + node server + ``` +1. In your browser, navigate to `http://localhost:3000` *(or the IP/hostname of the server and the PORT you defined earlier.)* +1. Login using the default administrator user: + - Email: `admin@example.com` + - Password: `12345678` -

GitHub Sponsors

+> **DO NOT** report bugs. This build is **VERY** buggy and **VERY** incomplete. Absolutely **NO** support is provided either. -Support this project by becoming a sponsor. Your name will show up in the Contribute page of all Wiki.js installations as well as here with a link to your website! [[Become a sponsor](https://github.com/users/NGPixel/sponsorship)] +## Using VS Code Dev Environment -
- - - - - - - -
- - - - - - - -
-
+### Requirements -
- - - - - - - - - - - - -
- - Alexander Casassovici
(@alexksso) -
-
- - Broxen
(@broxen) -
-
- - Dacon
(@xDacon) -
-
- - - - - - Jay Daley
(@JayDaley) -
-
- - Oleksii
(@idokka) -
-
- -
- - -- Akira Suenami ([@a-suenami](https://github.com/a-suenami)) -- 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)) -- Cloud Data Hosting LLC ([@CloudDataHostingLLC](https://github.com/CloudDataHostingLLC)) -- CrazyMarvin ([@CrazyMarvin](https://github.com/CrazyMarvin)) -- David Christian Holin ([@SirGibihm](https://github.com/SirGibihm)) -- Dragan Espenschied ([@despens](https://github.com/despens)) -- Elijah Zobenko ([@he110](https://github.com/he110)) -- 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)) -- Ian Hyzy ([@ianhyzy](https://github.com/ianhyzy)) -- Jaimyn Mayer ([@jabelone](https://github.com/jabelone)) -- Jay Lee ([@polyglotm](https://github.com/polyglotm)) -- Kelly Wardrop ([@dropcoded](https://github.com/dropcoded)) -- Loki ([@binaryloki](https://github.com/binaryloki)) -- MaFarine ([@MaFarine](https://github.com/MaFarine)) -- Marcilio Leite Neto ([@marclneto](https://github.com/marclneto)) - - - - -- Mattias Johnson ([@mattiasJohnson](https://github.com/mattiasJohnson)) -- Max Ricketts-Uy ([@MaxRickettsUy](https://github.com/MaxRickettsUy)) -- Mitchell Rowton ([@mrowton](https://github.com/mrowton)) -- M. Scott Ford ([@mscottford](https://github.com/mscottford)) -- Nick Halase ([@nhalase](https://github.com/nhalase)) -- Nina Reynolds ([@cutecycle](https://github.com/cutecycle)) -- Noel Cower ([@nilium](https://github.com/nilium)) -- Philipp Schmitt ([@pschmitt](https://github.com/pschmitt)) -- Robert Lanzke ([@winkelement](https://github.com/winkelement)) -- Sam Martin ([@ABitMoreDepth](https://github.com/ABitMoreDepth)) -- Sean Coffey ([@seanecoffey](https://github.com/seanecoffey)) -- Stephan Kristyn ([@stevek-pro](https://github.com/stevek-pro)) -- Theodore Chu ([@TheodoreChu](https://github.com/TheodoreChu)) -- Tyler Denman ([@tylerguy](https://github.com/tylerguy)) -- Victor Bilgin ([@vbilgin](https://github.com/vbilgin)) -- VMO Solutions ([@vmosolutions](https://github.com/vmosolutions)) -- aniketpanjwani ([@aniketpanjwani](https://github.com/aniketpanjwani)) -- aytaa ([@aytaa](https://github.com/aytaa)) -- magicpotato ([@fortheday](https://github.com/fortheday)) -- motoacs ([@motoacs](https://github.com/motoacs)) -- rburckner ([@rburckner](https://github.com/rburckner)) -- scorpion ([@scorpion](https://github.com/scorpion)) -- valantien ([@valantien](https://github.com/valantien)) - -
-
+- VS Code +- Docker Desktop +- **Windows-only:** WSL 2 + WSL Integration enabled in Docker Desktop -

OpenCollective Sponsors

+### Usage -Support this project by becoming a sponsor. Your logo will show up in the Contribute page of all Wiki.js installations as well as here with a link to your website! [[Become a sponsor](https://opencollective.com/wikijs#sponsor)] +1. Clone the project +1. Open the project in VS Code +1. Make sure you have **Dev Containers** extension installed. (On Windows, you need the **WSL** VS Code extension as well.) +1. Reopen the project in container (from the popup in the lower-right corner of the screen when opening the project, or via the Command Palette (Ctrl+Shift+P) afterwards). +1. Once in container mode, run the task "Create terminals" from the Command Palette: + - Launch the Command Palette (Ctrl+Shift+P) + - Type "Run Task" and press Enter + - Select the task "Create terminals" and press Enter +1. Two terminals will launch in split-screen mode at the bottom of the screen. **Server** on the left and **UX** on the right. +1. In the left-side terminal (Server), run the command: + ```sh + yarn legacy:build + ``` +1. In the right-side terminal (UX), run the command: + ```sh + yarn build + ``` +1. Back in the left-side terminal (Server), run the command: + ```sh + yarn dev + ``` +1. Open your browser to `http://localhost:3000` +1. Login using the default administrator user: + - Email: `admin@example.com` + - Password: `12345678` -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
-
+> **DO NOT** report bugs. This build is **VERY** buggy and **VERY** incomplete. Absolutely **NO** support is provided either. -

Patreon Backers

+### Server Development -Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/requarks)] +From the left-side terminal (Server), run the command: -
-
- - -- Al Romano -- Alex Balabanov -- Alex Zen -- Arti Zirk -- Brandon Curtis -- Dave 'Sri' Seah -- djagoo -- Douglas Lassance -- Ernie Reid -- Etienne -- Flemis Jurgenheimer -- Florent -- Günter Pavlas -- hong -- Hope -- Ian - - - - -- Iskander Callos -- Josh Stewart -- Justin Dunsworth -- Keir -- Loïc CRAMPON -- Ludgeir Ibanez -- Mark Mansur -- Matt Gedigian -- Patryk -- Philipp Schürch -- Tracey Duffy -- Richeir -- Shad Narcher -- SmartNET.works -- Stepan Sokolovskyi -- Zach Maynard -- 张白驹 - -
-
+```sh +yarn dev +``` + +This will launch the server and automatically restart upon modification of any server files. + +Only precompiled client assets are served in this mode. See the sections below on how to modify the frontend and run in SPA (Single Page Application) mode. -

OpenCollective Backers

+### Frontend Development (Quasar/Vue 3) -Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/wikijs#backer)] +> Make sure you are running `yarn dev` in the left-side terminal (Server) first! Requests still need to be forwarded to the server, even in SPA mode! - +If you wish to modify any frontend content (under `/ux`), you need to start the Quasar Dev Server in the right-side terminal (UX): -

Contributors

+```sh +yarn dev +``` -This project exists thanks to all the people who contribute. [[Contribute]](https://github.com/Requarks/wiki/blob/master/.github/CONTRIBUTING.md). - +You can then access the site at `http://localhost:3001`. Notice the port being `3001` rather than `3000`. The app runs in a SPA (single-page application) mode and automatically hot-reload any modified component. Any requests made to the `/graphql` endpoint are automatically forwarded to the server running on port `3000`, which is why both must be running at the same time. -

Special Thanks

+Note that not all sections/features are available from this mode, notably the page editing features which still relies on the old client code (Vuetify/Vue 2). For example, trying to edit a page will simply not work. You must use the normal mode (port 3000) to edit pages as it relies on legacy client code. As more features gets ported / developed for Vue 3, they will become available in the SPA mode. -![Algolia](https://js.wiki/legacy/logo_algolia.png) -[Algolia](https://www.algolia.com/) for providing access to their incredible search engine. +Any change you make to the frontend will not be reflected on port 3000 until you run the command `yarn build` in the right-side terminal. -![Browserstack](https://js.wiki/legacy/logo_browserstack.png) -[Browserstack](https://www.browserstack.com/) for providing access to their great cross-browser testing tools. +### Legacy Frontend Development (Vuetify/Vue 2) -![Cloudflare](https://js.wiki/legacy/logo_cloudflare.png) -[Cloudflare](https://www.cloudflare.com/) for providing their great CDN, SSL and advanced networking services. +Client code from Wiki.js 2.x is located under `/client`. Some sections still rely on this legacy code (notably the page editing features). Code is gradually being removed from this location and replaced with newer code in `/ux`. -![DigitalOcean](https://js.wiki/legacy/logo_digitalocean.png) -[DigitalOcean](https://m.do.co/c/5f7445bfa4d0) for providing hosting of the Wiki.js documentation site. +In the unlikely event that you need to modify legacy code and regenerate the old client files, you can do so by running in this command in the left-side terminal (Server): +```sh +yarn legacy:build +``` -![Icons8](https://static.requarks.io/logo/icons8-text-h40.png) -[Icons8](https://icons8.com/) for providing beautiful icon sets. +Then run `yarn dev` to start the server again. -![Lokalise](https://static.requarks.io/logo/lokalise-text-h40.png) -[Lokalise](https://lokalise.com/) for providing access to their great localization tool. +### pgAdmin -![Netlify](https://js.wiki/legacy/logo_netlify.png) -[Netlify](https://www.netlify.com) for providing hosting for landings and blog websites. +A web version of pgAdmin (a PostgreSQL administration tool) is available at `http://localhost:8000`. Use the login `dev` / `123123` to login. -![ngrok](https://static.requarks.io/logo/ngrok-h40.png) -[ngrok](https://ngrok.com) for providing access to their great HTTP tunneling services. +The server **dev** should already be available under **Servers**. If that's not the case, add a new one with the following settings: -![Porkbun](https://static.requarks.io/logo/porkbun.png) -[Porkbun](https://www.porkbun.com) for providing domain registration services. +- Hostname: `db` +- Port: `5432` +- Username: `postgres` +- Password: `postgres` +- Database: `postgres` diff --git a/client/components/editor.vue b/client/components/editor.vue index 170eb1f3..eaa959a0 100644 --- a/client/components/editor.vue +++ b/client/components/editor.vue @@ -141,8 +141,8 @@ export default { default: null }, pageId: { - type: Number, - default: 0 + type: String, + default: '' }, checkoutDate: { type: String, @@ -369,33 +369,32 @@ export default { // -> UPDATE EXISTING PAGE // -------------------------------------------- - const conflictResp = await this.$apollo.query({ - query: gql` - query ($id: Int!, $checkoutDate: Date!) { - pages { - checkConflicts(id: $id, checkoutDate: $checkoutDate) - } - } - `, - fetchPolicy: 'network-only', - variables: { - id: this.pageId, - checkoutDate: this.checkoutDateActive - } - }) - if (_.get(conflictResp, 'data.pages.checkConflicts', false)) { - this.$root.$emit('saveConflict') - throw new Error(this.$t('editor:conflict.warning')) - } + // const conflictResp = await this.$apollo.query({ + // query: gql` + // query ($id: Int!, $checkoutDate: Date!) { + // pages { + // checkConflicts(id: $id, checkoutDate: $checkoutDate) + // } + // } + // `, + // fetchPolicy: 'network-only', + // variables: { + // id: this.pageId, + // checkoutDate: this.checkoutDateActive + // } + // }) + // if (_.get(conflictResp, 'data.pages.checkConflicts', false)) { + // this.$root.$emit('saveConflict') + // throw new Error(this.$t('editor:conflict.warning')) + // } let resp = await this.$apollo.mutate({ mutation: gql` mutation ( - $id: Int! + $id: UUID! $content: String $description: String $editor: String - $isPrivate: Boolean $isPublished: Boolean $locale: String $path: String @@ -406,32 +405,27 @@ export default { $tags: [String] $title: String ) { - pages { - update( - id: $id - content: $content - description: $description - editor: $editor - isPrivate: $isPrivate - isPublished: $isPublished - locale: $locale - path: $path - publishEndDate: $publishEndDate - publishStartDate: $publishStartDate - scriptCss: $scriptCss - scriptJs: $scriptJs - tags: $tags - title: $title - ) { - operation { - succeeded - errorCode - slug - message - } - page { - updatedAt - } + updatePage( + id: $id + content: $content + description: $description + editor: $editor + isPublished: $isPublished + locale: $locale + path: $path + publishEndDate: $publishEndDate + publishStartDate: $publishStartDate + scriptCss: $scriptCss + scriptJs: $scriptJs + tags: $tags + title: $title + ) { + operation { + succeeded + message + } + page { + updatedAt } } } @@ -442,7 +436,6 @@ export default { description: this.$store.get('page/description'), editor: this.$store.get('editor/editorKey'), locale: this.$store.get('page/locale'), - isPrivate: false, isPublished: this.$store.get('page/isPublished'), path: this.$store.get('page/path'), publishEndDate: this.$store.get('page/publishEndDate') || '', @@ -453,7 +446,7 @@ export default { title: this.$store.get('page/title') } }) - resp = _.get(resp, 'data.pages.update', {}) + resp = _.get(resp, 'data.updatePage', {}) if (_.get(resp, 'operation.succeeded')) { this.checkoutDateActive = _.get(resp, 'page.updatedAt', this.checkoutDateActive) this.isConflict = false @@ -547,30 +540,30 @@ export default { styl.appendChild(document.createTextNode(css)) } }, 1000) - }, - apollo: { - isConflict: { - query: gql` - query ($id: Int!, $checkoutDate: Date!) { - pages { - checkConflicts(id: $id, checkoutDate: $checkoutDate) - } - } - `, - fetchPolicy: 'network-only', - pollInterval: 5000, - variables () { - return { - id: this.pageId, - checkoutDate: this.checkoutDateActive - } - }, - update: (data) => _.cloneDeep(data.pages.checkConflicts), - skip () { - return this.mode === 'create' || this.isSaving || !this.isDirty - } - } } + // apollo: { + // isConflict: { + // query: gql` + // query ($id: Int!, $checkoutDate: Date!) { + // pages { + // checkConflicts(id: $id, checkoutDate: $checkoutDate) + // } + // } + // `, + // fetchPolicy: 'network-only', + // pollInterval: 5000, + // variables () { + // return { + // id: this.pageId, + // checkoutDate: this.checkoutDateActive + // } + // }, + // update: (data) => _.cloneDeep(data.pages.checkConflicts), + // skip () { + // return this.mode === 'create' || this.isSaving || !this.isDirty + // } + // } + // } } diff --git a/server/controllers/common.js b/server/controllers/common.js index 34bacd88..21f4b21f 100644 --- a/server/controllers/common.js +++ b/server/controllers/common.js @@ -238,51 +238,6 @@ router.get(['/_edit', '/_edit/*'], async (req, res, next) => { js: '' } } - - // -> From Template - if (req.query.from && tmplCreateRegex.test(req.query.from)) { - let tmplPageId = 0 - let tmplVersionId = 0 - if (req.query.from.indexOf(',')) { - const q = req.query.from.split(',') - tmplPageId = _.toSafeInteger(q[0]) - tmplVersionId = _.toSafeInteger(q[1]) - } else { - tmplPageId = _.toSafeInteger(req.query.from) - } - - if (tmplVersionId > 0) { - // -> From Page Version - const pageVersion = await WIKI.db.pageHistory.getVersion({ pageId: tmplPageId, versionId: tmplVersionId }) - if (!pageVersion) { - _.set(res.locals, 'pageMeta.title', 'Page Not Found') - return res.status(404).render('notfound', { action: 'template' }) - } - if (!WIKI.auth.checkAccess(req.user, ['read:history'], { path: pageVersion.path, locale: pageVersion.locale })) { - _.set(res.locals, 'pageMeta.title', 'Unauthorized') - return res.render('unauthorized', { action: 'sourceVersion' }) - } - page.content = Buffer.from(pageVersion.content).toString('base64') - page.editorKey = pageVersion.editor - page.title = pageVersion.title - page.description = pageVersion.description - } else { - // -> From Page Live - const pageOriginal = await WIKI.db.pages.query().findById(tmplPageId) - if (!pageOriginal) { - _.set(res.locals, 'pageMeta.title', 'Page Not Found') - return res.status(404).render('notfound', { action: 'template' }) - } - if (!WIKI.auth.checkAccess(req.user, ['read:source'], { path: pageOriginal.path, locale: pageOriginal.locale })) { - _.set(res.locals, 'pageMeta.title', 'Unauthorized') - return res.render('unauthorized', { action: 'source' }) - } - page.content = Buffer.from(pageOriginal.content).toString('base64') - page.editorKey = pageOriginal.editorKey - page.title = pageOriginal.title - page.description = pageOriginal.description - } - } } res.render('editor', { page, injectCode, effectivePermissions }) diff --git a/server/core/asar.js b/server/core/asar.js index 2578c692..c1521934 100644 --- a/server/core/asar.js +++ b/server/core/asar.js @@ -9,7 +9,7 @@ const fs = require('fs') */ const packages = { - 'twemoji': path.join(WIKI.ROOTPATH, `assets/svg/twemoji.asar`) + 'twemoji': path.join(WIKI.ROOTPATH, `assets-legacy/svg/twemoji.asar`) } module.exports = { diff --git a/server/db/migrations/3.0.0.js b/server/db/migrations/3.0.0.js index 35c2af1a..377d85f6 100644 --- a/server/db/migrations/3.0.0.js +++ b/server/db/migrations/3.0.0.js @@ -603,7 +603,8 @@ exports.up = async knex => { auth: { [authModuleId]: { password: await bcrypt.hash(process.env.ADMIN_PASS || '12345678', 12), - mustChangePwd: !process.env.ADMIN_PASS, + mustChangePwd: false, // TODO: Revert to true (below) once change password flow is implemented + // mustChangePwd: !process.env.ADMIN_PASS, restrictLogin: false, tfaRequired: false, tfaSecret: '' diff --git a/server/graph/resolvers/page.js b/server/graph/resolvers/page.js index 7ca03b6f..09710808 100644 --- a/server/graph/resolvers/page.js +++ b/server/graph/resolvers/page.js @@ -1,5 +1,6 @@ const _ = require('lodash') const graphHelper = require('../../helpers/graph') +const pageHelper = require('../../helpers/page') module.exports = { Query: { @@ -139,7 +140,7 @@ module.exports = { return results }, /** - * FETCH SINGLE PAGE + * FETCH SINGLE PAGE BY ID */ async pageById (obj, args, context, info) { let page = await WIKI.db.pages.getPageFromDb(args.id) @@ -160,6 +161,22 @@ module.exports = { throw new WIKI.Error.PageNotFound() } }, + /** + * FETCH SINGLE PAGE BY PATH + */ + async pageByPath (obj, args, context, info) { + const pageArgs = pageHelper.parsePath(args.path) + let page = await WIKI.db.pages.getPageFromDb(pageArgs) + if (page) { + return { + ...page, + locale: page.localeCode, + editor: page.editorKey + } + } else { + throw new Error('ERR_PAGE_NOT_FOUND') + } + }, /** * FETCH TAGS */ @@ -366,7 +383,7 @@ module.exports = { user: context.req.user }) return { - responseResult: graphHelper.generateSuccess('Page created successfully.'), + operation: graphHelper.generateSuccess('Page created successfully.'), page } } catch (err) { @@ -383,7 +400,7 @@ module.exports = { user: context.req.user }) return { - responseResult: graphHelper.generateSuccess('Page has been updated.'), + operation: graphHelper.generateSuccess('Page has been updated.'), page } } catch (err) { diff --git a/server/graph/schemas/page.graphql b/server/graph/schemas/page.graphql index 5c48ee83..3d300cfe 100644 --- a/server/graph/schemas/page.graphql +++ b/server/graph/schemas/page.graphql @@ -34,6 +34,10 @@ extend type Query { id: Int! ): Page + pageByPath( + path: String! + ): Page + tags: [PageTag]! searchTags( @@ -80,7 +84,7 @@ extend type Mutation { ): PageResponse updatePage( - id: Int! + id: UUID! content: String description: String editor: String @@ -158,7 +162,7 @@ type PageMigrationResponse { } type Page { - id: Int + id: UUID path: String hash: String title: String diff --git a/server/models/pageHistory.js b/server/models/pageHistory.js index 33a5bff4..bcf72ec5 100644 --- a/server/models/pageHistory.js +++ b/server/models/pageHistory.js @@ -19,7 +19,7 @@ module.exports = class PageHistory extends Model { hash: {type: 'string'}, title: {type: 'string'}, description: {type: 'string'}, - isPublished: {type: 'boolean'}, + publishState: {type: 'string'}, publishStartDate: {type: 'string'}, publishEndDate: {type: 'string'}, content: {type: 'string'}, @@ -60,14 +60,6 @@ module.exports = class PageHistory extends Model { to: 'users.id' } }, - editor: { - relation: Model.BelongsToOneRelation, - modelClass: require('./editors'), - join: { - from: 'pageHistory.editorKey', - to: 'editors.key' - } - }, locale: { relation: Model.BelongsToOneRelation, modelClass: require('./locales'), @@ -89,18 +81,18 @@ module.exports = class PageHistory extends Model { static async addVersion(opts) { await WIKI.db.pageHistory.query().insert({ pageId: opts.id, + siteId: opts.siteId, authorId: opts.authorId, content: opts.content, contentType: opts.contentType, description: opts.description, - editorKey: opts.editorKey, + editor: opts.editor, hash: opts.hash, - isPrivate: (opts.isPrivate === true || opts.isPrivate === 1), - isPublished: (opts.isPublished === true || opts.isPublished === 1), + publishState: opts.publishState, localeCode: opts.localeCode, path: opts.path, - publishEndDate: opts.publishEndDate || '', - publishStartDate: opts.publishStartDate || '', + publishEndDate: opts.publishEndDate?.toISO(), + publishStartDate: opts.publishStartDate?.toISO(), title: opts.title, action: opts.action || 'updated', versionDate: opts.versionDate @@ -116,7 +108,6 @@ module.exports = class PageHistory extends Model { 'pageHistory.path', 'pageHistory.title', 'pageHistory.description', - 'pageHistory.isPrivate', 'pageHistory.isPublished', 'pageHistory.publishStartDate', 'pageHistory.publishEndDate', diff --git a/server/models/pages.js b/server/models/pages.js index 583a1777..3c374497 100644 --- a/server/models/pages.js +++ b/server/models/pages.js @@ -421,8 +421,8 @@ module.exports = class Page extends Model { content: opts.content, description: opts.description, publishState: opts.publishState, - publishEndDate: opts.publishEndDate || '', - publishStartDate: opts.publishStartDate || '', + publishEndDate: opts.publishEndDate?.toISO(), + publishStartDate: opts.publishStartDate?.toISO(), title: opts.title, extra: JSON.stringify({ ...ogPage.extra, @@ -439,18 +439,18 @@ module.exports = class Page extends Model { await WIKI.db.pages.renderPage(page) WIKI.events.outbound.emit('deletePageFromCache', page.hash) - // -> Update Search Index - const pageContents = await WIKI.db.pages.query().findById(page.id).select('render') - page.safeContent = WIKI.db.pages.cleanHTML(pageContents.render) - await WIKI.data.searchEngine.updated(page) + // // -> Update Search Index + // const pageContents = await WIKI.db.pages.query().findById(page.id).select('render') + // page.safeContent = WIKI.db.pages.cleanHTML(pageContents.render) + // await WIKI.data.searchEngine.updated(page) // -> Update on Storage - if (!opts.skipStorage) { - await WIKI.db.storage.pageEvent({ - event: 'updated', - page - }) - } + // if (!opts.skipStorage) { + // await WIKI.db.storage.pageEvent({ + // event: 'updated', + // page + // }) + // } // -> Perform move? if ((opts.locale && opts.locale !== page.localeCode) || (opts.path && opts.path !== page.path)) { diff --git a/server/views/base.pug b/server/views/base.pug index 3a4b32ca..6189c5e9 100644 --- a/server/views/base.pug +++ b/server/views/base.pug @@ -40,28 +40,20 @@ html(lang=siteConfig.lang) //- CSS - - link( - type='text/css' - rel='stylesheet' - href='/_assets-legacy/css/app.629ebe3c082227dbee31.css' - ) - - //- JS script( type='text/javascript' - src='/_assets-legacy/js/runtime.js?1664769154' + src='/_assets-legacy/js/runtime.js' ) script( type='text/javascript' - src='/_assets-legacy/js/app.js?1664769154' + src='/_assets-legacy/js/app.js' ) diff --git a/server/views/editor.pug b/server/views/editor.pug index b395cbec..322cdf76 100644 --- a/server/views/editor.pug +++ b/server/views/editor.pug @@ -7,7 +7,7 @@ block head block body #root editor( - :page-id=page.id + page-id=page.id locale=page.localeCode path=page.path title=page.title diff --git a/ux/.yarnrc.yml b/ux/.yarnrc.yml index 2067f48f..39757f21 100644 --- a/ux/.yarnrc.yml +++ b/ux/.yarnrc.yml @@ -5,18 +5,12 @@ enableTelemetry: false nodeLinker: node-modules packageExtensions: - '@quasar/vite-plugin@*': - dependencies: - 'quasar': '*' 'rollup-plugin-visualizer@*': dependencies: 'rollup': '*' 'v-network-graph@*': dependencies: 'd3-force': '*' - '@intlify/vite-plugin-vue-i18n@*': - dependencies: - 'vite': '*' plugins: - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs diff --git a/ux/quasar.config.js b/ux/quasar.config.js index ac81ea2b..9e50b7cb 100644 --- a/ux/quasar.config.js +++ b/ux/quasar.config.js @@ -77,6 +77,7 @@ module.exports = configure(function (/* ctx */) { extendViteConf (viteConf) { viteConf.build.assetsDir = '_assets' + // viteConf.resolve.alias.vue = '/workspace/ux/node_modules/vue/dist/vue.esm-bundler.js' // viteConf.build.rollupOptions = { // ...viteConf.build.rollupOptions ?? {}, // external: [ diff --git a/ux/src/components/BlueprintIcon.vue b/ux/src/components/BlueprintIcon.vue index 882d5116..1653d981 100644 --- a/ux/src/components/BlueprintIcon.vue +++ b/ux/src/components/BlueprintIcon.vue @@ -5,7 +5,7 @@ q-item-section(avatar) :text-color='avatarTextColor' font-size='14px' rounded - :style='hueRotate !== 0 ? `filter: hue-rotate(` + hueRotate + `deg)` : ``' + :style='props.hueRotate !== 0 ? `filter: hue-rotate(` + props.hueRotate + `deg)` : ``' ) q-badge( v-if='indicatorDot' @@ -13,57 +13,57 @@ q-item-section(avatar) :color='indicatorDot' floating ) - q-tooltip(v-if='indicatorText') {{indicatorText}} + q-tooltip(v-if='props.indicatorText') {{props.indicatorText}} q-icon( v-if='!textMode' :name='`img:/_assets/icons/ultraviolet-` + icon + `.svg`' size='sm' ) - span.text-uppercase(v-else) {{text}} + span.text-uppercase(v-else) {{props.text}} - diff --git a/ux/src/components/IconPickerDialog.vue b/ux/src/components/IconPickerDialog.vue index 31acee43..6686e3bb 100644 --- a/ux/src/components/IconPickerDialog.vue +++ b/ux/src/components/IconPickerDialog.vue @@ -1,7 +1,7 @@ -