├── .gitignore ├── README.md ├── config └── install │ └── views.view.react_watchdog.yml ├── js ├── .eslintignore ├── .eslintrc.json ├── README.md ├── dist │ └── helpers.js ├── package.json ├── src │ ├── components │ │ ├── app.js │ │ ├── elements │ │ │ ├── index.js │ │ │ ├── select.js │ │ │ ├── table.js │ │ │ └── tableHeader.js │ │ └── helpers │ │ │ └── loading.js │ └── index.js ├── webpack.config.dev.js ├── webpack.config.js └── yarn.lock ├── react_admin.info.yml ├── react_admin.libraries.yml ├── react_admin.routing.yml └── src └── Controller └── DblogController.php /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | js/dist/index.js 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Admin UI 2 | 3 | ## Setup 4 | 5 | Ensure you have a moderately recent version of [Node.js](https://nodejs.org/en/) (8.9.1LTS) and [Yarn](https://yarnpkg.com/en/) installed. Currently the bundle is not included as this is under active development. 6 | 7 | `cd js && yarn install && yarn run build:js` 8 | 9 | ## Development 10 | 11 | The watcher will continuously build the bundle while you are working. 12 | 13 | `cd js && yarn install && yarn run watch:js` 14 | -------------------------------------------------------------------------------- /config/install/views.view.react_watchdog.yml: -------------------------------------------------------------------------------- 1 | langcode: en 2 | status: true 3 | dependencies: 4 | config: 5 | - user.role.administrator 6 | - user.role.anonymous 7 | - user.role.authenticated 8 | module: 9 | - dblog 10 | - rest 11 | - serialization 12 | - user 13 | _core: 14 | default_config_hash: 3QZ9apklK6mQ7BzodmxzOxqO---2BCPtOLE3k9eQ0Is 15 | id: react_watchdog 16 | label: React Watchdog 17 | module: views 18 | description: 'Recent log messages' 19 | tag: '' 20 | base_table: watchdog 21 | base_field: wid 22 | core: 8.x 23 | display: 24 | default: 25 | display_plugin: default 26 | id: default 27 | display_title: Master 28 | position: 0 29 | display_options: 30 | access: 31 | type: perm 32 | options: 33 | perm: 'access site reports' 34 | cache: 35 | type: none 36 | options: { } 37 | query: 38 | type: views_query 39 | options: 40 | disable_sql_rewrite: false 41 | distinct: false 42 | replica: false 43 | query_comment: '' 44 | query_tags: { } 45 | exposed_form: 46 | type: basic 47 | options: 48 | submit_button: Filter 49 | reset_button: true 50 | reset_button_label: Reset 51 | exposed_sorts_label: 'Sort by' 52 | expose_sort_order: false 53 | sort_asc_label: Asc 54 | sort_desc_label: Desc 55 | pager: 56 | type: full 57 | options: 58 | items_per_page: 50 59 | offset: 0 60 | id: 0 61 | total_pages: null 62 | tags: 63 | previous: ‹‹ 64 | next: ›› 65 | first: '« First' 66 | last: 'Last »' 67 | expose: 68 | items_per_page: false 69 | items_per_page_label: 'Items per page' 70 | items_per_page_options: '5, 10, 25, 50' 71 | items_per_page_options_all: false 72 | items_per_page_options_all_label: '- All -' 73 | offset: false 74 | offset_label: Offset 75 | quantity: 9 76 | style: 77 | type: table 78 | options: 79 | grouping: { } 80 | row_class: '{{ type }} {{ severity }}' 81 | default_row_class: true 82 | override: true 83 | sticky: false 84 | caption: '' 85 | summary: '' 86 | description: '' 87 | columns: 88 | nothing: nothing 89 | wid: wid 90 | severity: severity 91 | type: type 92 | timestamp: timestamp 93 | message: message 94 | name: name 95 | link: link 96 | info: 97 | nothing: 98 | sortable: false 99 | default_sort_order: asc 100 | align: '' 101 | separator: '' 102 | empty_column: false 103 | responsive: priority-medium 104 | wid: 105 | sortable: false 106 | default_sort_order: desc 107 | align: '' 108 | separator: '' 109 | empty_column: false 110 | responsive: priority-low 111 | severity: 112 | sortable: false 113 | default_sort_order: asc 114 | align: '' 115 | separator: '' 116 | empty_column: false 117 | responsive: priority-low 118 | type: 119 | sortable: true 120 | default_sort_order: asc 121 | align: '' 122 | separator: '' 123 | empty_column: false 124 | responsive: priority-medium 125 | timestamp: 126 | sortable: true 127 | default_sort_order: desc 128 | align: '' 129 | separator: '' 130 | empty_column: false 131 | responsive: priority-low 132 | message: 133 | sortable: false 134 | default_sort_order: asc 135 | align: '' 136 | separator: '' 137 | empty_column: false 138 | responsive: '' 139 | name: 140 | sortable: true 141 | default_sort_order: asc 142 | align: '' 143 | separator: '' 144 | empty_column: false 145 | responsive: priority-medium 146 | link: 147 | align: '' 148 | separator: '' 149 | empty_column: false 150 | responsive: priority-low 151 | default: wid 152 | empty_table: false 153 | row: 154 | type: fields 155 | fields: 156 | nothing: 157 | id: nothing 158 | table: views 159 | field: nothing 160 | relationship: none 161 | group_type: group 162 | admin_label: Icon 163 | label: '' 164 | exclude: false 165 | alter: 166 | alter_text: true 167 | text: '' 168 | make_link: false 169 | path: '' 170 | absolute: false 171 | external: false 172 | replace_spaces: false 173 | path_case: none 174 | trim_whitespace: false 175 | alt: '' 176 | rel: '' 177 | link_class: '' 178 | prefix: '' 179 | suffix: '' 180 | target: '' 181 | nl2br: false 182 | max_length: 0 183 | word_boundary: true 184 | ellipsis: true 185 | more_link: false 186 | more_link_text: '' 187 | more_link_path: '' 188 | strip_tags: false 189 | trim: false 190 | preserve_tags: '' 191 | html: false 192 | element_type: '' 193 | element_class: icon 194 | element_label_type: '' 195 | element_label_class: '' 196 | element_label_colon: false 197 | element_wrapper_type: '' 198 | element_wrapper_class: '' 199 | element_default_classes: false 200 | empty: '' 201 | hide_empty: false 202 | empty_zero: false 203 | hide_alter_empty: false 204 | plugin_id: custom 205 | wid: 206 | id: wid 207 | table: watchdog 208 | field: wid 209 | relationship: none 210 | group_type: group 211 | admin_label: '' 212 | label: WID 213 | exclude: true 214 | alter: 215 | alter_text: false 216 | text: '' 217 | make_link: false 218 | path: '' 219 | absolute: false 220 | external: false 221 | replace_spaces: false 222 | path_case: none 223 | trim_whitespace: false 224 | alt: '' 225 | rel: '' 226 | link_class: '' 227 | prefix: '' 228 | suffix: '' 229 | target: '' 230 | nl2br: false 231 | max_length: 0 232 | word_boundary: true 233 | ellipsis: true 234 | more_link: false 235 | more_link_text: '' 236 | more_link_path: '' 237 | strip_tags: false 238 | trim: false 239 | preserve_tags: '' 240 | html: false 241 | element_type: '' 242 | element_class: '' 243 | element_label_type: '' 244 | element_label_class: '' 245 | element_label_colon: true 246 | element_wrapper_type: '' 247 | element_wrapper_class: '' 248 | element_default_classes: true 249 | empty: '' 250 | hide_empty: false 251 | empty_zero: false 252 | hide_alter_empty: true 253 | plugin_id: standard 254 | severity: 255 | id: severity 256 | table: watchdog 257 | field: severity 258 | relationship: none 259 | group_type: group 260 | admin_label: '' 261 | label: Severity 262 | exclude: true 263 | alter: 264 | alter_text: false 265 | text: '' 266 | make_link: false 267 | path: '' 268 | absolute: false 269 | external: false 270 | replace_spaces: false 271 | path_case: none 272 | trim_whitespace: false 273 | alt: '' 274 | rel: '' 275 | link_class: '' 276 | prefix: '' 277 | suffix: '' 278 | target: '' 279 | nl2br: false 280 | max_length: 0 281 | word_boundary: true 282 | ellipsis: true 283 | more_link: false 284 | more_link_text: '' 285 | more_link_path: '' 286 | strip_tags: false 287 | trim: false 288 | preserve_tags: '' 289 | html: false 290 | element_type: '' 291 | element_class: '' 292 | element_label_type: '' 293 | element_label_class: '' 294 | element_label_colon: true 295 | element_wrapper_type: '' 296 | element_wrapper_class: '' 297 | element_default_classes: true 298 | empty: '' 299 | hide_empty: false 300 | empty_zero: false 301 | hide_alter_empty: true 302 | machine_name: false 303 | plugin_id: machine_name 304 | type: 305 | id: type 306 | table: watchdog 307 | field: type 308 | relationship: none 309 | group_type: group 310 | admin_label: '' 311 | label: Type 312 | exclude: false 313 | alter: 314 | alter_text: false 315 | text: '' 316 | make_link: false 317 | path: '' 318 | absolute: false 319 | external: false 320 | replace_spaces: false 321 | path_case: none 322 | trim_whitespace: false 323 | alt: '' 324 | rel: '' 325 | link_class: '' 326 | prefix: '' 327 | suffix: '' 328 | target: '' 329 | nl2br: false 330 | max_length: 0 331 | word_boundary: true 332 | ellipsis: true 333 | more_link: false 334 | more_link_text: '' 335 | more_link_path: '' 336 | strip_tags: false 337 | trim: false 338 | preserve_tags: '' 339 | html: false 340 | element_type: '' 341 | element_class: '' 342 | element_label_type: '' 343 | element_label_class: '' 344 | element_label_colon: true 345 | element_wrapper_type: '' 346 | element_wrapper_class: '' 347 | element_default_classes: true 348 | empty: '' 349 | hide_empty: false 350 | empty_zero: false 351 | hide_alter_empty: true 352 | plugin_id: standard 353 | timestamp: 354 | id: timestamp 355 | table: watchdog 356 | field: timestamp 357 | relationship: none 358 | group_type: group 359 | admin_label: '' 360 | label: Date 361 | exclude: false 362 | alter: 363 | alter_text: false 364 | text: '' 365 | make_link: false 366 | path: '' 367 | absolute: false 368 | external: false 369 | replace_spaces: false 370 | path_case: none 371 | trim_whitespace: false 372 | alt: '' 373 | rel: '' 374 | link_class: '' 375 | prefix: '' 376 | suffix: '' 377 | target: '' 378 | nl2br: false 379 | max_length: 0 380 | word_boundary: true 381 | ellipsis: true 382 | more_link: false 383 | more_link_text: '' 384 | more_link_path: '' 385 | strip_tags: false 386 | trim: false 387 | preserve_tags: '' 388 | html: false 389 | element_type: '' 390 | element_class: '' 391 | element_label_type: '' 392 | element_label_class: '' 393 | element_label_colon: true 394 | element_wrapper_type: '' 395 | element_wrapper_class: '' 396 | element_default_classes: true 397 | empty: '' 398 | hide_empty: false 399 | empty_zero: false 400 | hide_alter_empty: true 401 | date_format: short 402 | custom_date_format: '' 403 | timezone: '' 404 | plugin_id: date 405 | message: 406 | id: message 407 | table: watchdog 408 | field: message 409 | relationship: none 410 | group_type: group 411 | admin_label: '' 412 | label: Message 413 | exclude: false 414 | alter: 415 | alter_text: false 416 | text: '' 417 | make_link: true 418 | path: 'admin/reports/dblog/event/{{ wid }}' 419 | absolute: false 420 | external: false 421 | replace_spaces: false 422 | path_case: none 423 | trim_whitespace: false 424 | alt: '{{ message }}' 425 | rel: '' 426 | link_class: '' 427 | prefix: '' 428 | suffix: '' 429 | target: '' 430 | nl2br: false 431 | max_length: 56 432 | word_boundary: true 433 | ellipsis: true 434 | more_link: false 435 | more_link_text: '' 436 | more_link_path: '' 437 | strip_tags: true 438 | trim: true 439 | preserve_tags: '' 440 | html: true 441 | element_type: '' 442 | element_class: '' 443 | element_label_type: '' 444 | element_label_class: '' 445 | element_label_colon: true 446 | element_wrapper_type: '' 447 | element_wrapper_class: '' 448 | element_default_classes: true 449 | empty: '' 450 | hide_empty: false 451 | empty_zero: false 452 | hide_alter_empty: true 453 | replace_variables: true 454 | plugin_id: dblog_message 455 | name: 456 | id: name 457 | table: users_field_data 458 | field: name 459 | relationship: uid 460 | group_type: group 461 | admin_label: '' 462 | label: User 463 | exclude: false 464 | alter: 465 | alter_text: false 466 | text: '' 467 | make_link: false 468 | path: '' 469 | absolute: false 470 | external: false 471 | replace_spaces: false 472 | path_case: none 473 | trim_whitespace: false 474 | alt: '' 475 | rel: '' 476 | link_class: '' 477 | prefix: '' 478 | suffix: '' 479 | target: '' 480 | nl2br: false 481 | max_length: 0 482 | word_boundary: true 483 | ellipsis: true 484 | more_link: false 485 | more_link_text: '' 486 | more_link_path: '' 487 | strip_tags: false 488 | trim: false 489 | preserve_tags: '' 490 | html: false 491 | element_type: '' 492 | element_class: '' 493 | element_label_type: '' 494 | element_label_class: '' 495 | element_label_colon: true 496 | element_wrapper_type: '' 497 | element_wrapper_class: '' 498 | element_default_classes: true 499 | empty: '' 500 | hide_empty: false 501 | empty_zero: false 502 | hide_alter_empty: true 503 | click_sort_column: value 504 | type: user_name 505 | settings: 506 | link_to_entity: true 507 | group_column: value 508 | group_columns: { } 509 | group_rows: true 510 | delta_limit: 0 511 | delta_offset: 0 512 | delta_reversed: false 513 | delta_first_last: false 514 | multi_type: separator 515 | separator: ', ' 516 | field_api_classes: false 517 | entity_type: user 518 | entity_field: name 519 | plugin_id: field 520 | link: 521 | id: link 522 | table: watchdog 523 | field: link 524 | relationship: none 525 | group_type: group 526 | admin_label: '' 527 | label: Operations 528 | exclude: false 529 | alter: 530 | alter_text: false 531 | text: '' 532 | make_link: false 533 | path: '' 534 | absolute: false 535 | external: false 536 | replace_spaces: false 537 | path_case: none 538 | trim_whitespace: false 539 | alt: '' 540 | rel: '' 541 | link_class: '' 542 | prefix: '' 543 | suffix: '' 544 | target: '' 545 | nl2br: false 546 | max_length: 0 547 | word_boundary: true 548 | ellipsis: true 549 | more_link: false 550 | more_link_text: '' 551 | more_link_path: '' 552 | strip_tags: false 553 | trim: false 554 | preserve_tags: '' 555 | html: false 556 | element_type: '' 557 | element_class: '' 558 | element_label_type: '' 559 | element_label_class: '' 560 | element_label_colon: true 561 | element_wrapper_type: '' 562 | element_wrapper_class: '' 563 | element_default_classes: true 564 | empty: '' 565 | hide_empty: false 566 | empty_zero: false 567 | hide_alter_empty: true 568 | plugin_id: dblog_operations 569 | filters: 570 | type: 571 | id: type 572 | table: watchdog 573 | field: type 574 | relationship: none 575 | group_type: group 576 | admin_label: '' 577 | operator: in 578 | value: { } 579 | group: 1 580 | exposed: true 581 | expose: 582 | operator_id: type_op 583 | label: Type 584 | description: '' 585 | use_operator: false 586 | operator: type_op 587 | identifier: type 588 | required: false 589 | remember: false 590 | multiple: true 591 | remember_roles: 592 | authenticated: authenticated 593 | anonymous: '0' 594 | administrator: '0' 595 | reduce: false 596 | is_grouped: false 597 | group_info: 598 | label: '' 599 | description: '' 600 | identifier: '' 601 | optional: true 602 | widget: select 603 | multiple: false 604 | remember: false 605 | default_group: All 606 | default_group_multiple: { } 607 | group_items: { } 608 | plugin_id: dblog_types 609 | severity: 610 | id: severity 611 | table: watchdog 612 | field: severity 613 | relationship: none 614 | group_type: group 615 | admin_label: '' 616 | operator: in 617 | value: { } 618 | group: 1 619 | exposed: true 620 | expose: 621 | operator_id: severity_op 622 | label: Severity 623 | description: '' 624 | use_operator: false 625 | operator: severity_op 626 | identifier: severity 627 | required: false 628 | remember: false 629 | multiple: true 630 | remember_roles: 631 | authenticated: authenticated 632 | anonymous: '0' 633 | administrator: '0' 634 | reduce: false 635 | is_grouped: false 636 | group_info: 637 | label: '' 638 | description: '' 639 | identifier: '' 640 | optional: true 641 | widget: select 642 | multiple: false 643 | remember: false 644 | default_group: All 645 | default_group_multiple: { } 646 | group_items: { } 647 | plugin_id: in_operator 648 | sorts: 649 | wid: 650 | id: wid 651 | table: watchdog 652 | field: wid 653 | relationship: none 654 | group_type: group 655 | admin_label: '' 656 | order: DESC 657 | exposed: true 658 | expose: 659 | label: WID 660 | plugin_id: standard 661 | type_asc: 662 | id: type_asc 663 | table: watchdog 664 | field: type 665 | relationship: none 666 | group_type: group 667 | admin_label: 'Type (asc)' 668 | order: ASC 669 | exposed: true 670 | expose: 671 | label: 'Type (asc)' 672 | plugin_id: standard 673 | type_desc: 674 | id: type_desc 675 | table: watchdog 676 | field: type 677 | relationship: none 678 | group_type: group 679 | admin_label: 'Type (desc)' 680 | order: DESC 681 | exposed: true 682 | expose: 683 | label: 'Type (desc)' 684 | plugin_id: standard 685 | timestamp_asc: 686 | id: timestamp_asc 687 | table: watchdog 688 | field: timestamp 689 | relationship: none 690 | group_type: group 691 | admin_label: '' 692 | order: ASC 693 | exposed: true 694 | expose: 695 | label: 'Timestamp (asc)' 696 | granularity: second 697 | plugin_id: date 698 | timestamp_desc: 699 | id: timestamp_desc 700 | table: watchdog 701 | field: timestamp 702 | relationship: none 703 | group_type: group 704 | admin_label: '' 705 | order: DESC 706 | exposed: true 707 | expose: 708 | label: 'Timestamp (desc)' 709 | granularity: second 710 | plugin_id: date 711 | name_asc: 712 | id: name_asc 713 | table: users_field_data 714 | field: name 715 | relationship: uid 716 | group_type: group 717 | admin_label: '' 718 | order: ASC 719 | exposed: true 720 | expose: 721 | label: 'User (asc)' 722 | entity_type: user 723 | entity_field: name 724 | plugin_id: standard 725 | name_desc: 726 | id: name_desc 727 | table: users_field_data 728 | field: name 729 | relationship: uid 730 | group_type: group 731 | admin_label: '' 732 | order: DESC 733 | exposed: true 734 | expose: 735 | label: 'User (desc)' 736 | entity_type: user 737 | entity_field: name 738 | plugin_id: standard 739 | title: 'Recent log messages' 740 | header: { } 741 | footer: { } 742 | empty: 743 | area: 744 | id: area 745 | table: views 746 | field: area 747 | relationship: none 748 | group_type: group 749 | admin_label: '' 750 | empty: true 751 | tokenize: false 752 | content: 753 | value: 'No log messages available.' 754 | format: basic_html 755 | plugin_id: text 756 | relationships: 757 | uid: 758 | id: uid 759 | table: watchdog 760 | field: uid 761 | relationship: none 762 | group_type: group 763 | admin_label: User 764 | required: false 765 | plugin_id: standard 766 | arguments: { } 767 | display_extenders: { } 768 | filter_groups: 769 | operator: AND 770 | groups: 771 | 1: AND 772 | css_class: admin-dblog 773 | cache_metadata: 774 | max-age: 0 775 | contexts: 776 | - 'languages:language_content' 777 | - 'languages:language_interface' 778 | - url 779 | - url.query_args 780 | - 'url.query_args:sort_by' 781 | - user.permissions 782 | tags: { } 783 | page: 784 | display_plugin: page 785 | id: page 786 | display_title: Page 787 | position: 1 788 | display_options: 789 | display_extenders: { } 790 | path: admin/reports/dblog 791 | sorts: { } 792 | defaults: 793 | sorts: false 794 | cache_metadata: 795 | max-age: 0 796 | contexts: 797 | - 'languages:language_content' 798 | - 'languages:language_interface' 799 | - url 800 | - url.query_args 801 | - user.permissions 802 | tags: { } 803 | rest_export_1: 804 | display_plugin: rest_export 805 | id: rest_export_1 806 | display_title: 'REST export' 807 | position: 2 808 | display_options: 809 | display_extenders: { } 810 | row: 811 | type: data_field 812 | options: 813 | field_options: 814 | type: 815 | alias: '' 816 | raw_output: false 817 | timestamp: 818 | alias: '' 819 | raw_output: false 820 | message: 821 | alias: '' 822 | raw_output: false 823 | name: 824 | alias: user 825 | raw_output: false 826 | link: 827 | alias: '' 828 | raw_output: false 829 | wid_1: 830 | alias: wid 831 | raw_output: false 832 | fields: 833 | wid_1: 834 | id: wid_1 835 | table: watchdog 836 | field: wid 837 | relationship: none 838 | group_type: group 839 | admin_label: '' 840 | label: wid 841 | exclude: false 842 | alter: 843 | alter_text: false 844 | text: '' 845 | make_link: false 846 | path: '' 847 | absolute: false 848 | external: false 849 | replace_spaces: false 850 | path_case: none 851 | trim_whitespace: false 852 | alt: '' 853 | rel: '' 854 | link_class: '' 855 | prefix: '' 856 | suffix: '' 857 | target: '' 858 | nl2br: false 859 | max_length: 0 860 | word_boundary: true 861 | ellipsis: true 862 | more_link: false 863 | more_link_text: '' 864 | more_link_path: '' 865 | strip_tags: false 866 | trim: false 867 | preserve_tags: '' 868 | html: false 869 | element_type: '' 870 | element_class: '' 871 | element_label_type: '' 872 | element_label_class: '' 873 | element_label_colon: false 874 | element_wrapper_type: '' 875 | element_wrapper_class: '' 876 | element_default_classes: true 877 | empty: '' 878 | hide_empty: false 879 | empty_zero: false 880 | hide_alter_empty: true 881 | plugin_id: standard 882 | type: 883 | id: type 884 | table: watchdog 885 | field: type 886 | relationship: none 887 | group_type: group 888 | admin_label: '' 889 | label: Type 890 | exclude: false 891 | alter: 892 | alter_text: false 893 | text: '' 894 | make_link: false 895 | path: '' 896 | absolute: false 897 | external: false 898 | replace_spaces: false 899 | path_case: none 900 | trim_whitespace: false 901 | alt: '' 902 | rel: '' 903 | link_class: '' 904 | prefix: '' 905 | suffix: '' 906 | target: '' 907 | nl2br: false 908 | max_length: 0 909 | word_boundary: true 910 | ellipsis: true 911 | more_link: false 912 | more_link_text: '' 913 | more_link_path: '' 914 | strip_tags: false 915 | trim: false 916 | preserve_tags: '' 917 | html: false 918 | element_type: '' 919 | element_class: '' 920 | element_label_type: '' 921 | element_label_class: '' 922 | element_label_colon: true 923 | element_wrapper_type: '' 924 | element_wrapper_class: '' 925 | element_default_classes: true 926 | empty: '' 927 | hide_empty: false 928 | empty_zero: false 929 | hide_alter_empty: true 930 | plugin_id: standard 931 | timestamp: 932 | id: timestamp 933 | table: watchdog 934 | field: timestamp 935 | relationship: none 936 | group_type: group 937 | admin_label: '' 938 | label: Date 939 | exclude: false 940 | alter: 941 | alter_text: false 942 | text: '' 943 | make_link: false 944 | path: '' 945 | absolute: false 946 | external: false 947 | replace_spaces: false 948 | path_case: none 949 | trim_whitespace: false 950 | alt: '' 951 | rel: '' 952 | link_class: '' 953 | prefix: '' 954 | suffix: '' 955 | target: '' 956 | nl2br: false 957 | max_length: 0 958 | word_boundary: true 959 | ellipsis: true 960 | more_link: false 961 | more_link_text: '' 962 | more_link_path: '' 963 | strip_tags: false 964 | trim: false 965 | preserve_tags: '' 966 | html: false 967 | element_type: '' 968 | element_class: '' 969 | element_label_type: '' 970 | element_label_class: '' 971 | element_label_colon: true 972 | element_wrapper_type: '' 973 | element_wrapper_class: '' 974 | element_default_classes: true 975 | empty: '' 976 | hide_empty: false 977 | empty_zero: false 978 | hide_alter_empty: true 979 | date_format: custom 980 | custom_date_format: 'm/d/o - H:i' 981 | timezone: '' 982 | plugin_id: date 983 | message: 984 | id: message 985 | table: watchdog 986 | field: message 987 | relationship: none 988 | group_type: group 989 | admin_label: '' 990 | label: Message 991 | exclude: false 992 | alter: 993 | alter_text: false 994 | text: '' 995 | make_link: false 996 | path: 'admin/reports/dblog/event/{{ wid }}' 997 | absolute: false 998 | external: false 999 | replace_spaces: false 1000 | path_case: none 1001 | trim_whitespace: false 1002 | alt: '{{ message }}' 1003 | rel: '' 1004 | link_class: '' 1005 | prefix: '' 1006 | suffix: '' 1007 | target: '' 1008 | nl2br: false 1009 | max_length: 56 1010 | word_boundary: true 1011 | ellipsis: true 1012 | more_link: false 1013 | more_link_text: '' 1014 | more_link_path: '' 1015 | strip_tags: true 1016 | trim: false 1017 | preserve_tags: '' 1018 | html: true 1019 | element_type: '' 1020 | element_class: '' 1021 | element_label_type: '' 1022 | element_label_class: '' 1023 | element_label_colon: true 1024 | element_wrapper_type: '' 1025 | element_wrapper_class: '' 1026 | element_default_classes: true 1027 | empty: '' 1028 | hide_empty: false 1029 | empty_zero: false 1030 | hide_alter_empty: true 1031 | replace_variables: true 1032 | plugin_id: dblog_message 1033 | name: 1034 | id: name 1035 | table: users_field_data 1036 | field: name 1037 | relationship: uid 1038 | group_type: group 1039 | admin_label: '' 1040 | label: User 1041 | exclude: false 1042 | alter: 1043 | alter_text: false 1044 | text: '' 1045 | make_link: false 1046 | path: '' 1047 | absolute: false 1048 | external: false 1049 | replace_spaces: false 1050 | path_case: none 1051 | trim_whitespace: false 1052 | alt: '' 1053 | rel: '' 1054 | link_class: '' 1055 | prefix: '' 1056 | suffix: '' 1057 | target: '' 1058 | nl2br: false 1059 | max_length: 0 1060 | word_boundary: true 1061 | ellipsis: true 1062 | more_link: false 1063 | more_link_text: '' 1064 | more_link_path: '' 1065 | strip_tags: true 1066 | trim: false 1067 | preserve_tags: '' 1068 | html: false 1069 | element_type: '' 1070 | element_class: '' 1071 | element_label_type: '' 1072 | element_label_class: '' 1073 | element_label_colon: true 1074 | element_wrapper_type: '' 1075 | element_wrapper_class: '' 1076 | element_default_classes: true 1077 | empty: '' 1078 | hide_empty: false 1079 | empty_zero: false 1080 | hide_alter_empty: true 1081 | click_sort_column: value 1082 | type: user_name 1083 | settings: 1084 | link_to_entity: true 1085 | group_column: value 1086 | group_columns: { } 1087 | group_rows: true 1088 | delta_limit: 0 1089 | delta_offset: 0 1090 | delta_reversed: false 1091 | delta_first_last: false 1092 | multi_type: separator 1093 | separator: ', ' 1094 | field_api_classes: false 1095 | entity_type: user 1096 | entity_field: name 1097 | plugin_id: field 1098 | link: 1099 | id: link 1100 | table: watchdog 1101 | field: link 1102 | relationship: none 1103 | group_type: group 1104 | admin_label: '' 1105 | label: Operations 1106 | exclude: false 1107 | alter: 1108 | alter_text: false 1109 | text: '' 1110 | make_link: false 1111 | path: '' 1112 | absolute: false 1113 | external: false 1114 | replace_spaces: false 1115 | path_case: none 1116 | trim_whitespace: false 1117 | alt: '' 1118 | rel: '' 1119 | link_class: '' 1120 | prefix: '' 1121 | suffix: '' 1122 | target: '' 1123 | nl2br: false 1124 | max_length: 0 1125 | word_boundary: true 1126 | ellipsis: true 1127 | more_link: false 1128 | more_link_text: '' 1129 | more_link_path: '' 1130 | strip_tags: false 1131 | trim: false 1132 | preserve_tags: '' 1133 | html: false 1134 | element_type: '' 1135 | element_class: '' 1136 | element_label_type: '' 1137 | element_label_class: '' 1138 | element_label_colon: true 1139 | element_wrapper_type: '' 1140 | element_wrapper_class: '' 1141 | element_default_classes: true 1142 | empty: '' 1143 | hide_empty: false 1144 | empty_zero: false 1145 | hide_alter_empty: true 1146 | plugin_id: dblog_operations 1147 | severity: 1148 | id: severity 1149 | table: watchdog 1150 | field: severity 1151 | relationship: none 1152 | group_type: group 1153 | admin_label: '' 1154 | label: '' 1155 | exclude: false 1156 | alter: 1157 | alter_text: false 1158 | text: '' 1159 | make_link: false 1160 | path: '' 1161 | absolute: false 1162 | external: false 1163 | replace_spaces: false 1164 | path_case: none 1165 | trim_whitespace: false 1166 | alt: '' 1167 | rel: '' 1168 | link_class: '' 1169 | prefix: '' 1170 | suffix: '' 1171 | target: '' 1172 | nl2br: false 1173 | max_length: 0 1174 | word_boundary: true 1175 | ellipsis: true 1176 | more_link: false 1177 | more_link_text: '' 1178 | more_link_path: '' 1179 | strip_tags: false 1180 | trim: false 1181 | preserve_tags: '' 1182 | html: false 1183 | element_type: '' 1184 | element_class: '' 1185 | element_label_type: '' 1186 | element_label_class: '' 1187 | element_label_colon: false 1188 | element_wrapper_type: '' 1189 | element_wrapper_class: '' 1190 | element_default_classes: true 1191 | empty: '' 1192 | hide_empty: false 1193 | empty_zero: false 1194 | hide_alter_empty: true 1195 | machine_name: false 1196 | plugin_id: machine_name 1197 | defaults: 1198 | fields: false 1199 | access: false 1200 | sorts: true 1201 | path: admin/reports/dblog/rest 1202 | pager: 1203 | type: mini 1204 | options: 1205 | items_per_page: 50 1206 | offset: 0 1207 | id: 0 1208 | total_pages: null 1209 | tags: 1210 | previous: '‹ Previous' 1211 | next: 'Next ›' 1212 | expose: 1213 | items_per_page: false 1214 | items_per_page_label: 'Items per page' 1215 | items_per_page_options: '5, 10, 25, 50' 1216 | items_per_page_options_all: false 1217 | items_per_page_options_all_label: '- All -' 1218 | offset: false 1219 | offset_label: Offset 1220 | access: 1221 | type: role 1222 | options: 1223 | role: 1224 | anonymous: anonymous 1225 | authenticated: authenticated 1226 | administrator: administrator 1227 | style: 1228 | type: serializer 1229 | options: 1230 | formats: 1231 | json: json 1232 | xml: xml 1233 | cache_metadata: 1234 | max-age: -1 1235 | contexts: 1236 | - 'languages:language_content' 1237 | - 'languages:language_interface' 1238 | - request_format 1239 | - url 1240 | - url.query_args 1241 | - 'url.query_args:sort_by' 1242 | - user.roles 1243 | tags: { } 1244 | -------------------------------------------------------------------------------- /js/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/**/*.js 2 | -------------------------------------------------------------------------------- /js/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-airbnb", 3 | "parser": "babel-eslint", 4 | "root": true, 5 | "env": { 6 | "browser": true, 7 | "es6": true 8 | }, 9 | "rules": { 10 | "brace-style": ["error", "stroustrup"], 11 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /js/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | yarn 3 | 4 | yarn run start:dev 5 | 6 | // to build 7 | yarn run build:js 8 | ``` 9 | -------------------------------------------------------------------------------- /js/dist/helpers.js: -------------------------------------------------------------------------------- 1 | (function(global){var babelHelpers=global.babelHelpers={};babelHelpers.typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(obj){return typeof obj}:function(obj){return obj&&"function"==typeof Symbol&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj},babelHelpers.jsx=function(){var REACT_ELEMENT_TYPE="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103;return function(type,props,key,children){var defaultProps=type&&type.defaultProps,childrenLength=arguments.length-3;if(props||0==childrenLength||(props={}),props&&defaultProps)for(var propName in defaultProps)void 0===props[propName]&&(props[propName]=defaultProps[propName]);else props||(props=defaultProps||{});if(1==childrenLength)props.children=children;else if(1", 6 | "license": "MIT", 7 | "scripts": { 8 | "watch:js": "./node_modules/.bin/webpack --watch --config webpack.config.dev.js", 9 | "lint:js": "./node_modules/.bin/eslint -c .eslintrc.json ./src", 10 | "build:js": "yarn run build:js-helpers && BABEL_ENV=production ./node_modules/.bin/webpack --progress --display-reasons --display-modules --config webpack.config.js", 11 | "build:js-helpers": "./node_modules/.bin/babel-external-helpers | ./node_modules/.bin/minify --mangle false > dist/helpers.js" 12 | }, 13 | "dependencies": { 14 | "prop-types": "^15.6.0", 15 | "qs": "^6.5.1", 16 | "react": "^16.0.0", 17 | "react-dom": "^16.0.0", 18 | "superagent": "^3.8.1" 19 | }, 20 | "devDependencies": { 21 | "babel-cli": "^6.26.0", 22 | "babel-core": "^6.26.0", 23 | "babel-eslint": "^8.0.1", 24 | "babel-loader": "^7.1.2", 25 | "babel-minify": "^0.2.0", 26 | "babel-minify-webpack-plugin": "^0.2.0", 27 | "babel-plugin-external-helpers": "^6.22.0", 28 | "babel-plugin-transform-class-properties": "^6.24.1", 29 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 30 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 31 | "babel-preset-env": "^1.6.0", 32 | "babel-preset-react": "^6.24.1", 33 | "eslint": "^3.19.0 || ^4.3.0", 34 | "eslint-config-airbnb": "^15.1.0", 35 | "eslint-plugin-import": "^2.7.0", 36 | "eslint-plugin-jsx-a11y": "^5.1.1", 37 | "eslint-plugin-react": "^7.1.0", 38 | "serve": "^6.1.0", 39 | "webpack": "^3.6.0", 40 | "webpack-dev-server": "^2.9.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /js/src/components/app.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import qs from 'qs'; 3 | import request from 'superagent'; 4 | 5 | import Loading from './helpers/loading'; 6 | import { Select, Table } from './elements'; 7 | 8 | const dblogEndpointUrl = `${window.location.origin}${drupalSettings.path.baseUrl}/admin/reports/dblog/rest`; 9 | 10 | export default class App extends Component { 11 | state = { 12 | data: [], 13 | loaded: false, 14 | buttonDisabled: false, 15 | page: 0, 16 | order: 'desc', 17 | sortBy: 'wid', 18 | filterParams: { 19 | _format: 'json', 20 | sort_by: 'wid', 21 | type: [], 22 | severity: [], 23 | }, 24 | } 25 | componentDidMount() { 26 | this.fetchLogEntries(this.state.page); 27 | } 28 | fetchLogEntries = (page) => { 29 | const queryString = qs.stringify( 30 | { ...this.state.filterParams, page: this.state.page }, 31 | { arrayFormat: 'brackets', encode: false }, 32 | ); 33 | this.setState({ buttonDisabled: true }, () => { 34 | request 35 | .get(`${dblogEndpointUrl}?${queryString}`) 36 | .end((err, { body }) => this.setState({ 37 | data: body, 38 | page, 39 | loaded: true, 40 | buttonDisabled: false, 41 | })); 42 | }); 43 | } 44 | sortHandler = (sort, order) => { 45 | this.setState({ 46 | order: (order === 'desc' && 'asc') || 'desc', 47 | sortBy: sort, 48 | filterParams: Object.assign(this.state.filterParams, { sort_by: `${sort}_${order}` }), 49 | }, () => this.fetchLogEntries(this.state.page)); 50 | } 51 | typeFilterHandler = (typeFilters) => { 52 | this.setState({ 53 | filterParams: Object.assign(this.state.filterParams, { type: Array.from(typeFilters) }), 54 | }, () => { 55 | this.fetchLogEntries(this.state.page); 56 | }); 57 | } 58 | severityFilterHandler = (severity) => { 59 | this.setState({ 60 | filterParams: Object.assign(this.state.filterParams, { severity: Array.from(severity) }), 61 | }, () => { 62 | this.fetchLogEntries(this.state.page); 63 | }); 64 | } 65 | nextPageHandler = (e) => { 66 | e.preventDefault(); 67 | this.setState((prevState) => ({ 68 | page: prevState.page + 1 69 | }), () => { 70 | this.fetchLogEntries(this.state.page); 71 | }); 72 | } 73 | previousPageHandler = (e) => { 74 | e.preventDefault(); 75 | if (this.state.page === 0) { 76 | return; 77 | } 78 | this.setState((prevState) => ({ 79 | page: prevState.page - 1 80 | }), () => { 81 | this.fetchLogEntries(this.state.page); 82 | }); 83 | } 84 | render() { 85 | return ( 86 |
87 | {this.state.loaded ? [ 88 |

The Database Logging module logs system events in the Drupal database. Monitor your site or debug site problems on this page.

, 89 |
90 |
91 | 124 |
125 |
, 126 | ] : } 140 |

141 | 147 | 153 |

154 | 155 | ); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /js/src/components/elements/index.js: -------------------------------------------------------------------------------- 1 | import Select from './select'; 2 | import Table from './table'; 3 | 4 | export { 5 | Select, 6 | Table, 7 | }; 8 | -------------------------------------------------------------------------------- /js/src/components/elements/select.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { arrayOf, string, func, shape } from 'prop-types'; 3 | 4 | export default class Select extends Component { 5 | static propTypes = { 6 | data: arrayOf(shape({ 7 | item: string, 8 | value: string, 9 | })).isRequired, 10 | label: string, 11 | onChange: func.isRequired, 12 | } 13 | static defaultProps = { 14 | label: '', 15 | } 16 | constructor({ onChange }) { 17 | super(); 18 | // @fixme State should be stored in this.state 19 | this.onChange = onChange; 20 | } 21 | changeHandler = (e) => { 22 | const selected = new Set( 23 | Array.from(e.target.options) 24 | .filter(option => option.selected) 25 | .map(option => option.value) 26 | ); 27 | this.onChange(selected); 28 | } 29 | render() { 30 | const { label, data, selected } = this.props; 31 | return [ 32 | label !== '' ? : '', 33 | , 38 | ]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /js/src/components/elements/table.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { arrayOf, string, shape, func } from 'prop-types'; 3 | 4 | import TableHeader from './tableHeader'; 5 | 6 | const Table = ({ entries, header, order, sortBy }) => ( 7 |
8 | 9 | 10 | {entries.map(entry => ( 11 | 12 | 14 | 15 | 16 | 17 | 19 | ))} 20 | 21 |
13 | {entry.type}{entry.timestamp}{`${entry.message.substring(0, 54)} …`}{entry.user} 18 |
22 | ); 23 | 24 | Table.propTypes = { 25 | entries: arrayOf(shape({ 26 | type: string, 27 | timestamp: string, 28 | message: string, 29 | user: string, 30 | wid: string, 31 | })).isRequired, 32 | header: arrayOf(shape({ 33 | txt: string.isRequired, 34 | callback: func, 35 | })).isRequired, 36 | order: string.isRequired, 37 | sortBy: string.isRequired, 38 | }; 39 | 40 | export default Table; 41 | -------------------------------------------------------------------------------- /js/src/components/elements/tableHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { arrayOf, string, func, shape } from 'prop-types'; 3 | 4 | const onClickSort = (entry, order) => (e) => { 5 | e.preventDefault(); 6 | entry.callback(entry.sort, order); 7 | }; 8 | 9 | const tableSortIndicator = (entry, order, sortBy) => { 10 | if (sortBy && entry.sort === sortBy) { 11 | return ( 12 | 13 | 14 | Sort descending 15 | 16 | 17 | ) 18 | } 19 | }; 20 | 21 | const TableHeader = ({ headerEntries, order, sortBy }) => ( 22 | 23 | 24 | { 25 | headerEntries.map(entry => ( 26 | 27 | {(entry.callback ? ( 28 | 33 | {entry.txt} 34 | {tableSortIndicator(entry, order, sortBy)} 35 | 36 | ) : ( 37 | {entry.txt} 38 | ))} 39 | 40 | )) 41 | } 42 | 43 | 44 | ); 45 | 46 | TableHeader.propTypes = { 47 | headerEntries: arrayOf(shape({ 48 | txt: string.isRequired, 49 | callback: func, 50 | })).isRequired, 51 | order: string.isRequired, 52 | sortBy: string.isRequired, 53 | }; 54 | 55 | export default TableHeader; 56 | -------------------------------------------------------------------------------- /js/src/components/helpers/loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default () => (

Loading

); 4 | -------------------------------------------------------------------------------- /js/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | 4 | import App from './components/app'; 5 | 6 | render(, document.getElementById('root')); 7 | -------------------------------------------------------------------------------- /js/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | module.exports = [ 5 | { 6 | entry: './src/index.js', 7 | output: { 8 | filename: 'index.js', 9 | path: path.resolve(__dirname, 'dist'), 10 | }, 11 | externals: { 12 | react: 'React', 13 | 'react-dom': 'ReactDOM', 14 | }, 15 | plugins: [ 16 | new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('development') } }), 17 | ], 18 | module: { 19 | loaders: [ 20 | { 21 | test: /\.js$/, 22 | loader: 'babel-loader', 23 | exclude: ['/node_modules/'], 24 | query: { 25 | plugins: [ 26 | 'external-helpers', 27 | 'transform-class-properties', 28 | 'transform-decorators-legacy', 29 | 'transform-object-rest-spread', 30 | ], 31 | presets: [ 32 | 'react', 33 | [ 34 | 'env', { 35 | modules: false, 36 | targets: { 37 | browsers: ['last 2 versions'], 38 | }, 39 | }, 40 | ], 41 | ], 42 | }, 43 | }, 44 | ], 45 | }, 46 | }, 47 | ]; 48 | -------------------------------------------------------------------------------- /js/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const webpack = require('webpack'); 4 | const Minify = require('babel-minify-webpack-plugin'); 5 | 6 | module.exports = [ 7 | { 8 | entry: './src/index.js', 9 | output: { 10 | filename: 'index.js', 11 | path: path.resolve(__dirname, 'dist'), 12 | }, 13 | plugins: [ 14 | new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production') } }), 15 | new Minify(), 16 | ], 17 | externals: { 18 | react: 'React', 19 | 'react-dom': 'ReactDOM', 20 | }, 21 | module: { 22 | loaders: [ 23 | { 24 | test: /\.js$/, 25 | loader: 'babel-loader', 26 | exclude: ['/node_modules/'], 27 | query: { 28 | plugins: [ 29 | 'external-helpers', 30 | 'transform-class-properties', 31 | 'transform-decorators-legacy', 32 | 'transform-object-rest-spread', 33 | ], 34 | presets: [ 35 | 'react', 36 | [ 37 | 'env', { 38 | modules: false, 39 | targets: { 40 | browsers: ['last 2 versions'], 41 | }, 42 | }, 43 | ], 44 | ], 45 | }, 46 | }, 47 | ], 48 | }, 49 | }, 50 | ]; 51 | -------------------------------------------------------------------------------- /react_admin.info.yml: -------------------------------------------------------------------------------- 1 | name: React admin 2 | description: Experimental React-based Drupal admin UI. 3 | # See discussion: https://www.drupal.org/project/ideas/issues/2913321 4 | core: 8.x 5 | type: module 6 | dependencies: 7 | - dblog 8 | - rest 9 | - serialization 10 | - views 11 | -------------------------------------------------------------------------------- /react_admin.libraries.yml: -------------------------------------------------------------------------------- 1 | dblog: 2 | js: 3 | https://unpkg.com/react@16/umd/react.production.min.js: 4 | external: true 5 | https://unpkg.com/react-dom@16/umd/react-dom.production.min.js: 6 | external: true 7 | js/dist/helpers.js: 8 | preprocess: false 9 | js/dist/index.js: 10 | preprocess: false 11 | 12 | dependencies: 13 | - core/drupalSettings 14 | - dblog/drupal.dblog 15 | -------------------------------------------------------------------------------- /react_admin.routing.yml: -------------------------------------------------------------------------------- 1 | react_admin.dblog_page: 2 | path: /admin/reports/dblog-react 3 | defaults: 4 | _controller: \Drupal\react_admin\Controller\DblogController::overview 5 | _title: 'Recent log messages' 6 | requirements: 7 | _permission: 'access site reports' 8 | -------------------------------------------------------------------------------- /src/Controller/DblogController.php: -------------------------------------------------------------------------------- 1 | '; 22 | 23 | return $build; 24 | } 25 | 26 | } 27 | --------------------------------------------------------------------------------