├── Documentation ├── Images │ ├── Dashboard.png │ ├── OnlineUsersWidget.png │ ├── StatusReportWidget.png │ └── PagesWithoutDescriptionWidget.png ├── genindex.rst ├── Sitemap.rst ├── Widgets │ ├── Index.rst │ ├── OnlineUsersWidget.rst │ ├── StatusReportWidget.rst │ └── PagesWithoutDescriptionWidget.rst ├── Introduction │ └── Index.rst ├── Includes.rst.txt ├── Installation │ └── Index.rst ├── Index.rst └── Settings.cfg ├── Resources ├── Public │ ├── Css │ │ ├── extendedListWidget.css │ │ └── reportsWidget.css │ └── Icons │ │ └── Extension.svg └── Private │ ├── Sass │ ├── _base.scss │ ├── extendedListWidget.scss │ └── reportsWidget.scss │ ├── Layouts │ └── Widget │ │ └── Widget.html │ ├── Templates │ └── Widget │ │ ├── ExtendedListWidget.html │ │ ├── PageOverviewWidget.html │ │ ├── PageWithoutMetaDescriptionWidget.html │ │ ├── StatusReportWidget.html │ │ └── UsersOnlineWidget.html │ └── Language │ └── locallang.xlf ├── Configuration ├── Backend │ └── DashboardWidgetGroups.php ├── Services.yaml └── Services.php ├── Classes └── Widgets │ ├── Provider │ ├── PageProviderInterface.php │ ├── UsersOnlineDataProvider.php │ ├── StatusReportButtonProvider.php │ └── PagesWithoutDescriptionDataProvider.php │ ├── ExtendedListWidget.php │ ├── PageOverviewWidget.php │ └── StatusReportWidget.php ├── .gitignore ├── ext_localconf.php ├── ext_emconf.php ├── .editorconfig ├── README.md ├── composer.json └── .sass-lint.yml /Documentation/Images/Dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FriendsOfTYPO3/widgets/HEAD/Documentation/Images/Dashboard.png -------------------------------------------------------------------------------- /Documentation/Images/OnlineUsersWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FriendsOfTYPO3/widgets/HEAD/Documentation/Images/OnlineUsersWidget.png -------------------------------------------------------------------------------- /Documentation/Images/StatusReportWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FriendsOfTYPO3/widgets/HEAD/Documentation/Images/StatusReportWidget.png -------------------------------------------------------------------------------- /Documentation/Images/PagesWithoutDescriptionWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FriendsOfTYPO3/widgets/HEAD/Documentation/Images/PagesWithoutDescriptionWidget.png -------------------------------------------------------------------------------- /Documentation/genindex.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | ===== 4 | Index 5 | ===== 6 | 7 | .. Sphinx will insert here the general index automatically. 8 | -------------------------------------------------------------------------------- /Resources/Public/Css/extendedListWidget.css: -------------------------------------------------------------------------------- 1 | .widget .widget-content-title-badge{display:flex}.widget .widget-content-badge-number{padding:5px 7px;margin-left:6px}.widget .widget-table-usertype{width:45px} -------------------------------------------------------------------------------- /Configuration/Backend/DashboardWidgetGroups.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'title' => 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widget_group.seo', 6 | ], 7 | ]; 8 | -------------------------------------------------------------------------------- /Resources/Private/Sass/_base.scss: -------------------------------------------------------------------------------- 1 | $danger: #c83c3c; 2 | $danger-bg: lighten($danger, 35%); 3 | $warning: #e8a33d; 4 | $warning-bg: lighten($warning, 35%); 5 | $success: #79a548; 6 | $success-bg: lighten($success, 35%); 7 | -------------------------------------------------------------------------------- /Documentation/Sitemap.rst: -------------------------------------------------------------------------------- 1 | :template: sitemap.html 2 | 3 | .. include:: /Includes.rst.txt 4 | 5 | ======= 6 | Sitemap 7 | ======= 8 | 9 | .. The sitemap.html template will insert here the page tree automatically. 10 | -------------------------------------------------------------------------------- /Classes/Widgets/Provider/PageProviderInterface.php: -------------------------------------------------------------------------------- 1 | 'Dashboard Widgets Collection', 4 | 'description' => 'A collection of widgets for the Dashboard of TYPO3', 5 | 'category' => 'fe', 6 | 'author' => 'Richard Haeser, Koen Wouters', 7 | 'state' => 'stable', 8 | 'version' => '1.1.0-dev', 9 | 'constraints' => [ 10 | 'depends' => [ 11 | 'typo3' => '10.4.0 - 11.0.99', 12 | 'dashboard' => '10.4.0 - 11.0.99' 13 | ], 14 | 'conflicts' => [], 15 | 'suggests' => [], 16 | ], 17 | 'autoload' => [ 18 | 'psr-4' => [ 19 | 'FriendsOfTYPO3\Widgets\\' => 'Classes' 20 | ] 21 | ], 22 | ]; 23 | -------------------------------------------------------------------------------- /Documentation/Widgets/OnlineUsersWidget.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | .. _online-users-widget: 4 | 5 | =========================== 6 | Current Online Users Widget 7 | =========================== 8 | 9 | This widget will show you who is currently logged in in the backend of your 10 | TYPO3 installation. This can be quite useful when you want to do maintenance 11 | and need to know if people are still using the installation. 12 | 13 | .. figure:: /Images/OnlineUsersWidget.png 14 | :class: with-shadow 15 | :alt: Show the current online users 16 | 17 | An overview of the current online users 18 | 19 | 20 | Options 21 | ------- 22 | There are no options available for this widget. 23 | -------------------------------------------------------------------------------- /Resources/Private/Layouts/Widget/Widget.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | {f:translate(id: configuration.title, default: configuration.title)} 5 | 6 |
7 | 8 |
9 | 10 |
11 | 12 | 13 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Documentation/Includes.rst.txt: -------------------------------------------------------------------------------- 1 | .. More information about this file: 2 | https://docs.typo3.org/m/typo3/docs-how-to-document/main/en-us/GeneralConventions/FileStructure.html#includes-rst-txt 3 | 4 | .. ---------- 5 | .. text roles 6 | .. ---------- 7 | 8 | .. role:: aspect(emphasis) 9 | .. role:: bash(code) 10 | .. role:: html(code) 11 | .. role:: js(code) 12 | .. role:: php(code) 13 | .. role:: rst(code) 14 | .. role:: sep(strong) 15 | .. role:: sql(code) 16 | 17 | .. role:: tsconfig(code) 18 | :class: typoscript 19 | 20 | .. role:: typoscript(code) 21 | .. role:: xml(code) 22 | :class: html 23 | 24 | .. role:: yaml(code) 25 | 26 | .. default-role:: code 27 | 28 | .. --------- 29 | .. highlight 30 | .. --------- 31 | 32 | .. By default, code blocks use PHP syntax highlighting 33 | 34 | .. highlight:: php 35 | -------------------------------------------------------------------------------- /Resources/Private/Templates/Widget/ExtendedListWidget.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
{item}
12 |
13 | 14 |
15 | 16 | 17 | {f:translate(id: button.title, default: button.title)} 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Resources/Public/Icons/Extension.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Resources/Private/Sass/reportsWidget.scss: -------------------------------------------------------------------------------- 1 | @import "Base"; 2 | 3 | .widget { 4 | &.widget-identifier-widgets-statusReport { 5 | .widget-table-wrapper { 6 | margin-top: -20px; 7 | margin-bottom: -20px; 8 | } 9 | 10 | .status-report { 11 | margin-top: -20px; 12 | } 13 | 14 | td { 15 | padding: 20px; 16 | } 17 | 18 | .contenttable { 19 | background-color: rgba(#fff, 0.2); 20 | 21 | tr:nth-child(even), 22 | thead tr { 23 | background-color: rgba(#fff, 0.4); 24 | } 25 | } 26 | 27 | .widget-content-footer { 28 | padding-top: 20px; 29 | } 30 | 31 | .status-report-severity-1 { 32 | background-color: $warning-bg; 33 | } 34 | 35 | .status-report-severity-2 { 36 | background-color: $danger-bg; 37 | } 38 | 39 | .status-report-severity-0 { 40 | background-color: $success-bg; 41 | } 42 | 43 | .widget-success-wrapper { 44 | display: flex; 45 | justify-content: center; 46 | align-items: center; 47 | height: 100%; 48 | font-weight: bold; 49 | color: $success; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Resources/Public/Css/reportsWidget.css: -------------------------------------------------------------------------------- 1 | .widget.widget-identifier-widgets-statusReport .widget-table-wrapper{margin-top:-20px;margin-bottom:-20px}.widget.widget-identifier-widgets-statusReport .status-report{margin-top:-20px}.widget.widget-identifier-widgets-statusReport td{padding:20px}.widget.widget-identifier-widgets-statusReport .contenttable{background-color:rgba(255,255,255,.2)}.widget.widget-identifier-widgets-statusReport .contenttable thead tr,.widget.widget-identifier-widgets-statusReport .contenttable tr:nth-child(even){background-color:rgba(255,255,255,.4)}.widget.widget-identifier-widgets-statusReport .widget-content-footer{padding-top:20px}.widget.widget-identifier-widgets-statusReport .status-report-severity-1{background-color:#fbefdd}.widget.widget-identifier-widgets-statusReport .status-report-severity-2{background-color:#efc7c7}.widget.widget-identifier-widgets-statusReport .status-report-severity-0{background-color:#d1e2bd}.widget.widget-identifier-widgets-statusReport .widget-success-wrapper{display:flex;justify-content:center;align-items:center;height:100%;font-weight:700;color:#79a548} -------------------------------------------------------------------------------- /Documentation/Installation/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | .. highlight:: bash 3 | 4 | .. _installation: 5 | 6 | ============ 7 | Installation 8 | ============ 9 | 10 | Target group: **Administrators** 11 | 12 | Installation with composer 13 | ========================== 14 | 15 | Check whether you are already using the extension with:: 16 | 17 | composer show | grep widgets 18 | 19 | This should either give you no result or something similar to::: 20 | 21 | friendsoftypo3/widgets v1.0.0 Dashboard Widgets for TYPO3. 22 | 23 | If it is not yet installed, use the ``composer require`` command to install the extension:: 24 | 25 | composer require friendsoftypo3/widgets 26 | 27 | 28 | Now head over to the extension manager and activate the extension. 29 | 30 | Installation without composer 31 | ============================= 32 | 33 | You can simply install stable versions of EXT:widgets using the Extension Manager 34 | from the TYPO3 backend. 35 | 36 | #. Go to the **Extension Manager**, select **Get Extensions** and search for 37 | "widgets". 38 | #. Install the extension. 39 | #. Activate the extension. 40 | #. Have fun! 41 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | indent_style = space 11 | indent_size = 4 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | 15 | # TS/JS-Files 16 | [*.{ts,js}] 17 | indent_size = 2 18 | 19 | # SCSS-Files 20 | [*.scss] 21 | indent_style = tab 22 | indent_size = 2 23 | 24 | # JSON-Files 25 | [*.json] 26 | indent_style = tab 27 | 28 | # ReST-Files 29 | [*.{rst,rst.txt}] 30 | indent_size = 3 31 | max_line_length = 80 32 | 33 | # Markdown-Files 34 | [*.md] 35 | max_line_length = 80 36 | 37 | # YAML-Files 38 | [*.{yaml,yml}] 39 | indent_size = 2 40 | 41 | # package.json 42 | # .travis.yml 43 | [{package.json,.travis.yml}] 44 | indent_size = 2 45 | 46 | # TypoScript 47 | [*.{typoscript,tsconfig}] 48 | indent_size = 2 49 | 50 | # XLF-Files 51 | [*.xlf] 52 | indent_style = tab 53 | 54 | # SQL-Files 55 | [*.sql] 56 | indent_style = tab 57 | indent_size = 2 58 | 59 | # .htaccess 60 | [{_.htaccess,.htaccess}] 61 | indent_style = tab 62 | -------------------------------------------------------------------------------- /Documentation/Widgets/StatusReportWidget.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | .. _status-report-widget: 4 | 5 | ==================== 6 | Status Report Widget 7 | ==================== 8 | 9 | This widget will give you an overview of all possible problems in your installation. 10 | You can also click on the link to go to the reports module. 11 | 12 | .. figure:: /Images/StatusReportWidget.png 13 | :class: with-shadow 14 | :alt: An example of the Status Report Widget 15 | 16 | This is how the Status Report widget could look like. 17 | 18 | .. important:: 19 | 20 | This widget is only available when you have 21 | `EXT:reports `__ 22 | installed and activated. 23 | 24 | 25 | Options 26 | ------- 27 | 28 | This widget has some options. To override the default options, see 29 | ":ref:`ext_dashboard:adjust-settings-of-widget`" in the dashboard documentation. 30 | 31 | .. confval:: showErrors 32 | 33 | :type: bool 34 | :default: true 35 | 36 | Define if you want to show reports with the severity error in your widget. 37 | 38 | .. confval:: showWarnings 39 | 40 | :type: bool 41 | :default: false 42 | 43 | Define if you want to show reports with the severity warning in your widget. 44 | -------------------------------------------------------------------------------- /Documentation/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | ============================ 4 | Dashboard Widgets Collection 5 | ============================ 6 | 7 | :Extension key: 8 | widgets 9 | 10 | :Package name: 11 | friendsoftypo3/widgets 12 | 13 | :Version: 14 | |release| 15 | 16 | :Language: 17 | en 18 | 19 | :Author: 20 | Richard Haeser, Koen Wouters & Contributors 21 | 22 | :License: 23 | This document is published under the 24 | `Creative Commons BY-NC-SA 4.0 `__ 25 | license. 26 | 27 | :Rendered: 28 | |today| 29 | 30 | ---- 31 | 32 | This extension contains various widgets that can be used on the TYPO3 backend 33 | :doc:`dashboard `. 34 | 35 | It currently contains the following widgets: 36 | 37 | * **Current Online Users**: Shows which users are currently online. 38 | * **Status Report**: Gives you an overview of errors and warnings in your 39 | installation. 40 | * **Pages without meta description**: Provides a list of recently edited pages 41 | that lack a meta description. 42 | 43 | ---- 44 | 45 | **Table of Contents:** 46 | 47 | .. toctree:: 48 | :maxdepth: 2 49 | :titlesonly: 50 | 51 | Introduction/Index 52 | Installation/Index 53 | Widgets/Index 54 | 55 | .. Meta Menu 56 | 57 | .. toctree:: 58 | :hidden: 59 | 60 | Sitemap 61 | genindex 62 | -------------------------------------------------------------------------------- /Resources/Private/Templates/Widget/PageOverviewWidget.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | 21 | 22 |
{page.title}
{page.slug}
16 | 17 | 18 | 19 |
23 |
24 | 25 |
26 | 27 | 28 | {f:translate(id: button.title, default: button.title)} 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Classes/Widgets/Provider/UsersOnlineDataProvider.php: -------------------------------------------------------------------------------- 1 | backendUserRepository = $backendUserRepository; 24 | $this->backendUserSessionRepository = $backendUserSessionRepository; 25 | } 26 | 27 | public function getItems(): array 28 | { 29 | $onlineUsersAndSessions = []; 30 | $onlineUsers = $this->backendUserRepository->findOnline(); 31 | foreach ($onlineUsers as $onlineUser) { 32 | $onlineUsersAndSessions[] = [ 33 | 'backendUser' => $onlineUser, 34 | 'sessions' => $this->backendUserSessionRepository->findByBackendUser($onlineUser) 35 | ]; 36 | } 37 | 38 | return $onlineUsersAndSessions; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Classes/Widgets/Provider/StatusReportButtonProvider.php: -------------------------------------------------------------------------------- 1 | title = $title; 32 | $this->target = $target; 33 | } 34 | 35 | public function getTitle(): string 36 | { 37 | return $this->title; 38 | } 39 | 40 | public function getLink(): string 41 | { 42 | $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); 43 | return (string)$uriBuilder->buildUriFromRoute( 44 | 'system_reports', 45 | ['action' => 'detail', 'extension' => 'tx_reports', 'report' => 'status'] 46 | ); 47 | } 48 | 49 | public function getTarget(): string 50 | { 51 | return $this->target; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Latest Stable Version](https://poser.pugx.org/friendsoftypo3/widgets/v/stable.svg)](https://extensions.typo3.org/extension/widgets/) 2 | [![TYPO3 10](https://img.shields.io/badge/TYPO3-10-orange.svg?style=flat-square)](https://get.typo3.org/version/10) 3 | [![Total Downloads](https://poser.pugx.org/friendsoftypo3/widgets/d/total.svg)](https://packagist.org/packages/friendsoftypo3/widgets) 4 | [![Monthly Downloads](https://poser.pugx.org/friendsoftypo3/widgets/d/monthly)](https://packagist.org/packages/friendsoftypo3/widgets) 5 | 6 | # TYPO3 extension `widgets` 7 | 8 | This extension contains various widgets that can be used on the TYPO3 backend 9 | [dashboard](https://docs.typo3.org/c/typo3/cms-dashboard/main/en-us/). 10 | 11 | It currently contains the following widgets: 12 | 13 | * **Current Online Users**: Shows which users are currently online. 14 | * **Status Report**: Gives you an overview of errors and warnings in your 15 | installation. 16 | * **Pages without meta description**: Provides a list of recently edited pages 17 | that lack a meta description. 18 | 19 | | | URL | 20 | |------------------|-------------------------------------------------------------| 21 | | **Repository:** | https://github.com/FriendsOfTYPO3/widgets | 22 | | **Read online:** | https://docs.typo3.org/p/friendsoftypo3/widgets/main/en-us/ | 23 | | **TER:** | https://extensions.typo3.org/extension/widgets | 24 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "friendsoftypo3/widgets", 3 | "type": "typo3-cms-extension", 4 | "description": "Dashboard Widgets Collection", 5 | "minimum-stability": "dev", 6 | "homepage": "https://extensions.typo3.org/extension/widgets", 7 | "support": { 8 | "docs": "https://docs.typo3.org/p/friendsoftypo3/widgets/main/en-us/", 9 | "issues": "https://github.com/FriendsOfTYPO3/widgets/issues", 10 | "source": "https://github.com/FriendsOfTYPO3/widgets" 11 | }, 12 | "license": "GPL-2.0-or-later", 13 | "authors": [ 14 | { 15 | "name": "Richard Haeser", 16 | "role": "Developer" 17 | }, 18 | { 19 | "name": "Koen Wouters", 20 | "role": "Developer" 21 | } 22 | ], 23 | "require": { 24 | "typo3/cms-core": "^10.4 || 11.0.*@dev", 25 | "typo3/cms-dashboard": "^10.4 || 11.0.*@dev" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "FriendsOfTYPO3\\Widgets\\": "Classes/" 30 | } 31 | }, 32 | "require-dev": { 33 | "friendsofphp/php-cs-fixer": "^2.15", 34 | "typo3/testing-framework": "^4.9 || ^5.0", 35 | "phpstan/phpstan": "^0.12.0@dev" 36 | }, 37 | "scripts": { 38 | "test:php:unit": [ 39 | "phpunit -c build/phpunit.xml" 40 | ], 41 | "test": [ 42 | "@test:php:unit" 43 | ], 44 | "cgl": [ 45 | "php-cs-fixer fix -v --dry-run --using-cache false" 46 | ], 47 | "cgl-fix": [ 48 | "php-cs-fixer fix -v --using-cache false" 49 | ] 50 | }, 51 | "extra": { 52 | "typo3/cms": { 53 | "extension-key": "widgets" 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Resources/Private/Templates/Widget/PageWithoutMetaDescriptionWidget.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 |
{page.title}
{page.slug}
{page.tstamp} 18 | 19 | 20 | 21 |
25 |
26 | 27 |
28 | 29 | 30 | {f:translate(id: button.title, default: button.title)} 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Documentation/Widgets/PagesWithoutDescriptionWidget.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | .. _pages-without-description-widget: 4 | 5 | ===================================== 6 | Pages without Meta Description Widget 7 | ===================================== 8 | 9 | If you want to optimise your pages for search engines, it is quite important 10 | to write unique and informative meta descriptions. Having no meta description 11 | is most of the times giving you unexpected results in search engines. 12 | 13 | This widget will show you the last edited pages without a meta description 14 | specified. You can click on the pencil icon behind every page to directly edit 15 | the page properties of the specific page. 16 | 17 | .. figure:: /Images/PagesWithoutDescriptionWidget.png 18 | :class: with-shadow 19 | :alt: This widget is showing the last edited pages without a meta description 20 | 21 | This widget is showing the last edited pages without a meta description 22 | 23 | .. important:: 24 | 25 | This widget is only available when you have 26 | `EXT:seo `__ 27 | installed and activated. 28 | 29 | Options 30 | ------- 31 | 32 | This widget has some options. To override the default options, see 33 | ":ref:`ext_dashboard:adjust-settings-of-widget`" in the dashboard documentation. 34 | 35 | .. confval:: excludedDoktypes 36 | 37 | :type: string 38 | :default: ``3, 4, 6, 7, 199, 254, 255`` 39 | 40 | Some doktypes are not real pages and can be excluded from this overview. 41 | 42 | .. confval:: limit 43 | 44 | :type: int 45 | :default: ``8`` 46 | 47 | The number of pages without a meta description to show within the widget. 48 | 49 | An example: 50 | 51 | :file:`Configuration/Services.yaml`:: 52 | 53 | FriendsOfTYPO3\Widgets\Widgets\Provider\PagesWithoutDescriptionDataProvider: 54 | arguments: 55 | $excludedDoktypes: [3, 4, 6, 7, 199, 254, 255] 56 | $limit: 8 57 | -------------------------------------------------------------------------------- /Resources/Private/Templates/Widget/StatusReportWidget.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
{f:translate(id: configuration.title, default: configuration.title)}{reports}
6 |
7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 21 | 22 | 23 | 24 |
17 |
{categoryReports.1.title}
18 |
{categoryReports.0}
19 |

{categoryReports.1.message}

20 |
25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 | 37 | {f:translate(id: button.title, default: button.title)} 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Configuration/Services.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | _defaults: 3 | autowire: true 4 | autoconfigure: true 5 | public: false 6 | 7 | FriendsOfTYPO3\Widgets\: 8 | resource: '../Classes/*' 9 | 10 | FriendsOfTYPO3\Widgets\Widgets\Provider\PagesWithoutDescriptionDataProvider: 11 | arguments: 12 | $excludedDoktypes: [3, 4, 6, 7, 199, 254, 255] 13 | $limit: 8 14 | 15 | FriendsOfTYPO3\Widgets\Widgets\Provider\StatusReportButtonProvider: 16 | arguments: 17 | $title: 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widgets.dashboard.widget.statusReport.button.title' 18 | 19 | widgets.dashboard.widget.onlineUsers: 20 | class: 'FriendsOfTYPO3\Widgets\Widgets\ExtendedListWidget' 21 | arguments: 22 | $dataProvider: '@FriendsOfTYPO3\Widgets\Widgets\Provider\UsersOnlineDataProvider' 23 | $view: '@dashboard.views.widget' 24 | $options: 25 | template: 'Widget/UsersOnlineWidget' 26 | tags: 27 | - name: dashboard.widget 28 | identifier: 'widgets-onlineUsers' 29 | groupNames: 'systemInfo' 30 | title: 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widgets.dashboard.widget.onlineUsers.title' 31 | description: 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widgets.dashboard.widget.onlineUsers.description' 32 | iconIdentifier: 'content-widget-list' 33 | height: 'large' 34 | width: 'medium' 35 | 36 | dashboard.widget.reports: 37 | class: 'FriendsOfTYPO3\Widgets\Widgets\StatusReportWidget' 38 | arguments: 39 | $view: '@dashboard.views.widget' 40 | $buttonProvider: '@FriendsOfTYPO3\Widgets\Widgets\Provider\StatusReportButtonProvider' 41 | $options: 42 | template: 'Widget/UsersOnlineWidget' 43 | tags: 44 | - name: dashboard.widget 45 | identifier: 'widgets-statusReport' 46 | groupNames: 'systemInfo' 47 | title: 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widgets.dashboard.widget.statusReport.title' 48 | description: 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widgets.dashboard.widget.statusReport.description' 49 | iconIdentifier: 'content-widget-list' 50 | height: 'medium' 51 | width: 'medium' 52 | -------------------------------------------------------------------------------- /Classes/Widgets/ExtendedListWidget.php: -------------------------------------------------------------------------------- 1 | configuration = $configuration; 43 | $this->dataProvider = $dataProvider; 44 | $this->view = $view; 45 | $this->buttonProvider = $buttonProvider; 46 | $this->options = array_merge( 47 | [ 48 | 'template' => 'Widget/ExtendedListWidget', 49 | ], 50 | $options 51 | ); 52 | } 53 | 54 | public function getCssFiles(): array 55 | { 56 | return [ 57 | 'EXT:widgets/Resources/Public/Css/extendedListWidget.css', 58 | ]; 59 | } 60 | 61 | public function renderWidgetContent(): string 62 | { 63 | $this->view->setTemplate($this->options['template']); 64 | 65 | $this->view->assignMultiple([ 66 | 'items' => $this->dataProvider->getItems(), 67 | 'options' => $this->options, 68 | 'currentUser' => $this->getBackendUser(), 69 | 'button' => $this->buttonProvider, 70 | 'configuration' => $this->configuration, 71 | 'dateFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], 72 | 'timeFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], 73 | ]); 74 | return $this->view->render(); 75 | } 76 | 77 | protected function getBackendUser(): BackendUserAuthentication 78 | { 79 | return $GLOBALS['BE_USER']; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Classes/Widgets/Provider/PagesWithoutDescriptionDataProvider.php: -------------------------------------------------------------------------------- 1 | excludedDoktypes = $excludedDoktypes; 27 | $this->limit = $limit ?: 5; 28 | } 29 | 30 | public function getPages(): array 31 | { 32 | $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); 33 | 34 | $constraints = [ 35 | $queryBuilder->expr()->notIn('doktype', $this->excludedDoktypes), 36 | $queryBuilder->expr()->eq('no_index', 0), 37 | $queryBuilder->expr()->orX( 38 | $queryBuilder->expr()->eq('description', $queryBuilder->createNamedParameter('')), 39 | $queryBuilder->expr()->isNull('description') 40 | ), 41 | ]; 42 | 43 | $items = []; 44 | $counter = 0; 45 | $iterator = 0; 46 | 47 | while ($counter < $this->limit) { 48 | $row = $queryBuilder 49 | ->select('*') 50 | ->from('pages') 51 | ->where(...$constraints) 52 | ->orderBy('tstamp', 'DESC') 53 | ->setFirstResult($iterator) 54 | ->setMaxResults(1) 55 | ->execute() 56 | ->fetch(); 57 | 58 | $iterator++; 59 | 60 | // If the $row is false, no row is returned from database. All matched $items in array will be returned. 61 | if($row === false) { 62 | return $items; 63 | } 64 | 65 | if (!$this->getBackendUser()->doesUserHaveAccess($row, Permission::PAGE_SHOW)) { 66 | continue; 67 | } 68 | 69 | $items[] = $row; 70 | $counter++; 71 | } 72 | return $items; 73 | } 74 | 75 | protected function getBackendUser(): BackendUserAuthentication 76 | { 77 | return $GLOBALS['BE_USER']; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Classes/Widgets/PageOverviewWidget.php: -------------------------------------------------------------------------------- 1 | configuration = $configuration; 44 | $this->dataProvider = $dataProvider; 45 | $this->view = $view; 46 | $this->buttonProvider = $buttonProvider; 47 | $this->options = array_merge( 48 | [ 49 | 'template' => 'Widget/ExtendedListWidget', 50 | ], 51 | $options 52 | ); 53 | } 54 | 55 | public function getCssFiles(): array 56 | { 57 | return [ 58 | 'EXT:widgets/Resources/Public/Css/extendedListWidget.css', 59 | ]; 60 | } 61 | 62 | public function renderWidgetContent(): string 63 | { 64 | $this->view->setTemplate($this->options['template']); 65 | 66 | $this->view->assignMultiple([ 67 | 'pages' => $this->dataProvider->getPages(), 68 | 'options' => $this->options, 69 | 'button' => $this->buttonProvider, 70 | 'configuration' => $this->configuration, 71 | 'dateFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], 72 | 'timeFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], 73 | ]); 74 | return $this->view->render(); 75 | } 76 | 77 | protected function getBackendUser(): BackendUserAuthentication 78 | { 79 | return $GLOBALS['BE_USER']; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Resources/Private/Templates/Widget/UsersOnlineWidget.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
{f:translate(id: configuration.title, default: configuration.title)}{items}
6 |
7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 33 | 34 | 35 | 36 | 37 |
/
23 | {onlineUser.backendUser.userName} 24 | 25 | 26 | 27 |
28 | {onlineUser.backendUser.realName}
30 | 31 | {session.ip}
38 |
39 |
40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Resources/Private/Language/locallang.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | Type 8 | 9 | 10 | User Type: Admin 11 | 12 | 13 | User Type: Editor 14 | 15 | 16 | Username 17 | 18 | 19 | Real Name 20 | 21 | 22 | Last access 23 | 24 | 25 | IP address 26 | 27 | 28 | You 29 | 30 | 31 | No problems found! 32 | 33 | 34 | Page 35 | 36 | 37 | Last change 38 | 39 | 40 | Current online users 41 | 42 | 43 | Will show you which users are currently online 44 | 45 | 46 | Open full Status Report 47 | 48 | 49 | Status Report 50 | 51 | 52 | Gives you an overview of errors and warnings in your installation 53 | 54 | 55 | Pages without Meta Description 56 | 57 | 58 | Returns a list of last edited pages without a Meta Description 59 | 60 | 61 | SEO 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /Configuration/Services.php: -------------------------------------------------------------------------------- 1 | services(); 16 | 17 | if (ExtensionManagementUtility::isLoaded('reports')) { 18 | $services->set('widgets.dashboard.widget.statusReport') 19 | ->class(StatusReportWidget::class) 20 | ->arg('$view', new Reference('dashboard.views.widget')) 21 | ->arg('$buttonProvider', new Reference('FriendsOfTYPO3\Widgets\Widgets\Provider\StatusReportButtonProvider')) 22 | ->tag( 23 | 'dashboard.widget', 24 | [ 25 | 'identifier' => 'widgets-statusReport', 26 | 'groupNames' => 'systemInfo', 27 | 'title' => 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widgets.dashboard.widget.statusReport.title', 28 | 'description' => 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widgets.dashboard.widget.statusReport.description', 29 | 'iconIdentifier' => 'content-widget-list', 30 | 'height' => 'medium', 31 | 'width' => 'medium' 32 | ] 33 | ) 34 | ; 35 | } 36 | 37 | if (ExtensionManagementUtility::isLoaded('seo')) { 38 | $services->set('widgets.dashboard.widget.pagesWithoutMetaDescription') 39 | ->class(PageOverviewWidget::class) 40 | ->arg('$dataProvider', new Reference('FriendsOfTYPO3\Widgets\Widgets\Provider\PagesWithoutDescriptionDataProvider')) 41 | ->arg('$view', new Reference('dashboard.views.widget')) 42 | ->arg('$buttonProvider', null) 43 | ->arg('$options', ['template' => 'Widget/PageWithoutMetaDescriptionWidget']) 44 | ->tag( 45 | 'dashboard.widget', 46 | [ 47 | 'identifier' => 'widgets-pagesWithoutMetaDescription', 48 | 'groupNames' => 'seo', 49 | 'title' => 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widgets.dashboard.widget.pagesWithoutMetaDescription.title', 50 | 'description' => 'LLL:EXT:widgets/Resources/Private/Language/locallang.xlf:widgets.dashboard.widget.pagesWithoutMetaDescription.description', 51 | 'iconIdentifier' => 'content-widget-list', 52 | 'height' => 'large', 53 | 'width' => 'medium' 54 | ] 55 | ) 56 | ; 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /Documentation/Settings.cfg: -------------------------------------------------------------------------------- 1 | # More information about this file: 2 | # https://docs.typo3.org/m/typo3/docs-how-to-document/main/en-us/GeneralConventions/FileStructure.html#settings-cfg 3 | 4 | [general] 5 | 6 | project = Dashboard Widgets Collection 7 | version = main (development) 8 | release = main (development) 9 | copyright = since 2020 by the TYPO3 contributors 10 | 11 | [html_theme_options] 12 | 13 | # "Edit on GitHub" button 14 | github_repository = FriendsOfTYPO3/widgets 15 | github_branch = master 16 | 17 | # Footer links 18 | project_home = https://extensions.typo3.org/extension/widgets 19 | project_contact = https://typo3.slack.com/archives/C025BQLFA 20 | project_repository = https://github.com/FriendsOfTYPO3/widgets 21 | project_issues = https://github.com/FriendsOfTYPO3/widgets/issues 22 | project_discussions = 23 | 24 | use_opensearch = 25 | 26 | [intersphinx_mapping] 27 | 28 | # Official TYPO3 manuals 29 | # h2document = https://docs.typo3.org/m/typo3/docs-how-to-document/main/en-us/ 30 | # t3cheatsheets = https://docs.typo3.org/m/typo3/docs-cheatsheets/main/en-us/ 31 | # t3contribute = https://docs.typo3.org/m/typo3/guide-contributionworkflow/main/en-us/ 32 | # t3coreapi = https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ 33 | # t3docteam = https://docs.typo3.org/m/typo3/team-t3docteam/main/en-us/ 34 | # t3editors = https://docs.typo3.org/m/typo3/tutorial-editors/main/en-us/ 35 | # t3extbasebook = https://docs.typo3.org/m/typo3/book-extbasefluid/main/en-us/ 36 | # t3extexample = https://docs.typo3.org/m/typo3/guide-example-extension-manual/main/en-us/ 37 | # t3home = https://docs.typo3.org/ 38 | # t3install = https://docs.typo3.org/m/typo3/guide-installation/main/en-us/ 39 | # t3l10n = https://docs.typo3.org/m/typo3/guide-frontendlocalization/main/en-us/ 40 | # t3sitepackage = https://docs.typo3.org/m/typo3/tutorial-sitepackage/main/en-us/ 41 | # t3start = https://docs.typo3.org/m/typo3/tutorial-getting-started/main/en-us/ 42 | # t3tca = https://docs.typo3.org/m/typo3/reference-tca/main/en-us/ 43 | # t3templating = https://docs.typo3.org/m/typo3/tutorial-templating/main/en-us/ 44 | # t3translate = https://docs.typo3.org/m/typo3/guide-frontendlocalization/main/en-us/ 45 | # t3tsconfig = https://docs.typo3.org/m/typo3/reference-tsconfig/main/en-us/ 46 | # t3tsref = https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/ 47 | # t3ts45 = https://docs.typo3.org/m/typo3/tutorial-typoscript-in-45-minutes/main/en-us/ 48 | # t3viewhelper = https://docs.typo3.org/other/typo3/view-helper-reference/main/en-us/ 49 | # t3upgrade = https://docs.typo3.org/m/typo3/guide-installation/main/en-us/ 50 | 51 | # TYPO3 system extensions 52 | # ext_adminpanel = https://docs.typo3.org/c/typo3/cms-adminpanel/main/en-us/ 53 | # ext_core = https://docs.typo3.org/c/typo3/cms-core/main/en-us/ 54 | ext_dashboard = https://docs.typo3.org/c/typo3/cms-dashboard/10.4/en-us/ 55 | # ext_felogin = https://docs.typo3.org/c/typo3/cms-felogin/main/en-us/ 56 | # ext_form = https://docs.typo3.org/c/typo3/cms-form/main/en-us/ 57 | # ext_fsc = https://docs.typo3.org/c/typo3/cms-fluid-styled-content/main/en-us/ 58 | # ext_indexed_search = https://docs.typo3.org/c/typo3/cms-indexed-search/main/en-us/ 59 | # ext_rte_ckeditor = https://docs.typo3.org/c/typo3/cms-rte-ckeditor/main/en-us/ 60 | # ext_scheduler = https://docs.typo3.org/c/typo3/cms-scheduler/main/en-us/ 61 | # ext_seo = https://docs.typo3.org/c/typo3/cms-seo/main/en-us/ 62 | # ext_workspaces = https://docs.typo3.org/c/typo3/cms-workspaces/main/en-us/ 63 | -------------------------------------------------------------------------------- /Classes/Widgets/StatusReportWidget.php: -------------------------------------------------------------------------------- 1 | configuration = $configuration; 39 | $this->view = $view; 40 | $this->buttonProvider = $buttonProvider; 41 | $this->options = array_merge( 42 | [ 43 | 'showErrors' => true, 44 | 'showWarnings' => false 45 | ], 46 | $options 47 | ); 48 | } 49 | 50 | protected function getStatusProvider($statusProvider) 51 | { 52 | if (strpos($statusProvider, 'LLL:') === 0) { 53 | // Label provided by extension 54 | $label = $this->getLanguageService()->sL($statusProvider); 55 | } else { 56 | // Generic label 57 | $label = $this->getLanguageService()->getLL('status_' . $statusProvider); 58 | } 59 | return empty($label) ? $statusProvider : $label; 60 | } 61 | 62 | public function renderWidgetContent(): string 63 | { 64 | $this->view->setTemplate('Widget/StatusReportWidget'); 65 | 66 | $this->view->assignMultiple([ 67 | 'options' => $this->options, 68 | 'reports' => $this->getWarningsAndErrors(), 69 | 'button' => $this->buttonProvider, 70 | 'configuration' => $this->configuration, 71 | 'dateFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], 72 | 'timeFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], 73 | ]); 74 | return $this->view->render(); 75 | } 76 | 77 | public function getCssFiles(): array 78 | { 79 | return [ 80 | 'EXT:widgets/Resources/Public/Css/reportsWidget.css', 81 | ]; 82 | } 83 | 84 | protected function getWarningsAndErrors(): array 85 | { 86 | $statusReport = GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Report\Status\Status::class); 87 | $allowedSeverities = []; 88 | 89 | if ($this->options['showErrors']) { 90 | $allowedSeverities[] = ReportStatus::ERROR; 91 | } 92 | if ($this->options['showWarnings']) { 93 | $allowedSeverities[] = ReportStatus::WARNING; 94 | } 95 | 96 | return $this->sortAndFilterStatuses($statusReport->getSystemStatus(), $allowedSeverities); 97 | } 98 | 99 | protected function sortAndFilterStatuses(array $systemStatus, array $allowedSeverities) 100 | { 101 | $statuses = []; 102 | $sortTitle = []; 103 | $header = null; 104 | /** @var ReportStatus $status */ 105 | foreach ($systemStatus as $provider => $statusCollection) { 106 | foreach ($statusCollection as $status) { 107 | if (in_array($status->getSeverity(), $allowedSeverities)) { 108 | $statuses[] = [$this->getStatusProvider($provider), $status]; 109 | $sortTitle[] = $status->getSeverity(); 110 | } 111 | } 112 | } 113 | array_multisort($sortTitle, SORT_DESC, $statuses); 114 | return $statuses; 115 | } 116 | 117 | /** 118 | * @return LanguageService 119 | */ 120 | protected function getLanguageService() 121 | { 122 | return $GLOBALS['LANG']; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /.sass-lint.yml: -------------------------------------------------------------------------------- 1 | options: 2 | formatter: stylish 3 | merge-default-rules: false 4 | rules: 5 | border-zero: 6 | - 2 7 | - convention: '0' 8 | brace-style: 9 | - 2 10 | - allow-single-line: false 11 | clean-import-paths: 12 | - 2 13 | - leading-underscore: false 14 | - filename-extension: false 15 | empty-line-between-blocks: 16 | - 2 17 | - allow-single-line-rulesets: false 18 | extends-before-declarations: 2 19 | extends-before-mixins: 2 20 | hex-length: 21 | - 2 22 | - style: short 23 | hex-notation: 24 | - 2 25 | - style: lowercase 26 | indentation: 27 | - 2 28 | - size: 'tab' 29 | leading-zero: 30 | - 2 31 | - include: true 32 | mixins-before-declarations: 33 | - 2 34 | - exclude: ['breakpoint'] 35 | nesting-depth: 36 | - 2 37 | - max-depth: 4 38 | no-color-keywords: 2 39 | no-debug: 2 40 | no-duplicate-properties: 41 | - 2 42 | - exclude: ['src'] 43 | no-empty-rulesets: 2 44 | no-invalid-hex: 2 45 | no-mergeable-selectors: 46 | - 2 47 | - whitelist: [] 48 | no-misspelled-properties: 49 | - 2 50 | no-trailing-whitespace: 2 51 | no-trailing-zero: 2 52 | no-transition-all: 2 53 | no-url-protocols: 2 54 | no-vendor-prefixes: 0 55 | no-warn: 2 56 | one-declaration-per-line: 2 57 | placeholder-in-extend: 2 58 | property-sort-order: 59 | - 2 60 | - ignore-custom-properties: false 61 | order: 62 | - content 63 | - counter-reset 64 | - counter-increment 65 | - position 66 | - top 67 | - right 68 | - bottom 69 | - left 70 | - z-index 71 | - display 72 | - flex-direction 73 | - flex-wrap 74 | - flex-flow 75 | - justify-content 76 | - align-items 77 | - align-content 78 | - order 79 | - flex-grow 80 | - flex-shrink 81 | - flex-basis 82 | - flex 83 | - align-self 84 | - columns 85 | - column-width 86 | - column-count 87 | - column-gap 88 | - column-rule 89 | - column-rule-width 90 | - column-rule-style 91 | - column-rule-color 92 | - column-span 93 | - column-fill 94 | - break-before 95 | - break-after 96 | - break-inside 97 | - overflow 98 | - overflow-x 99 | - overflow-y 100 | - overflow-wrap 101 | - overflow-style 102 | - clear 103 | - float 104 | - box-sizing 105 | - width 106 | - min-width 107 | - max-width 108 | - height 109 | - min-height 110 | - max-height 111 | - line-height 112 | - resize 113 | - padding 114 | - padding-top 115 | - padding-right 116 | - padding-bottom 117 | - padding-left 118 | - border 119 | - border-top 120 | - border-right 121 | - border-bottom 122 | - border-left 123 | - border-width 124 | - border-top-width 125 | - border-right-width 126 | - border-bottom-width 127 | - border-left-width 128 | - border-image 129 | - border-style 130 | - border-top-style 131 | - border-right-style 132 | - border-bottom-style 133 | - border-left-style 134 | - border-color 135 | - border-top-color 136 | - border-right-color 137 | - border-bottom-color 138 | - border-left-color 139 | - border-radius 140 | - border-top-left-radius 141 | - border-top-right-radius 142 | - border-bottom-right-radius 143 | - border-bottom-left-radius 144 | - margin 145 | - margin-top 146 | - margin-right 147 | - margin-bottom 148 | - margin-left 149 | - vertical-align 150 | - visibility 151 | - opacity 152 | - filter 153 | - list-style 154 | - list-style-type 155 | - list-style-position 156 | - list-style-image 157 | - background 158 | - background-size 159 | - background-clip 160 | - background-image 161 | - background-position 162 | - background-position-x 163 | - background-position-y 164 | - background-attachment 165 | - background-repeat 166 | - background-repeat-x 167 | - background-repeat-y 168 | - background-color 169 | - background-blend-mode 170 | - background-origin 171 | - outline 172 | - outline-width 173 | - outline-offset 174 | - outline-style 175 | - outline-color 176 | - box-shadow 177 | - font-family 178 | - src 179 | - font-weight 180 | - font-style 181 | - font-size 182 | - color 183 | - text-transform 184 | - text-align 185 | - text-shadow 186 | - word-spacing 187 | - letter-spacing 188 | - white-space 189 | - word-wrap 190 | - word-break 191 | - transform 192 | - transform-origin 193 | - transform-origin-x 194 | - transform-origin-y 195 | - transform-origin-z 196 | - transition 197 | - transition-property 198 | - transition-duration 199 | - transition-timing-function 200 | - transition-delay 201 | - will-change 202 | - cursor 203 | - backface-visibility 204 | quotes: 205 | - 2 206 | - style: double 207 | shorthand-values: 2 208 | single-line-per-selector: 2 209 | space-after-bang: 210 | - 2 211 | - include: false 212 | space-after-colon: 213 | - 2 214 | - include: true 215 | space-after-comma: 216 | - 2 217 | - include: true 218 | space-around-operator: 219 | - 2 220 | - include: true 221 | space-before-bang: 222 | - 2 223 | - include: true 224 | space-before-brace: 225 | - 2 226 | - include: true 227 | space-before-colon: 228 | - 2 229 | - include: false 230 | space-between-parens: 231 | - 2 232 | - include: false 233 | trailing-semicolon: 234 | - 2 235 | - include: true 236 | url-quotes: 237 | - 2 238 | zero-unit: 239 | - 2 240 | - include: false 241 | --------------------------------------------------------------------------------