ASPR-3010 Recommended plugin installation on IDEA startup

This commit is contained in:
Artem Orlov
2026-02-13 15:40:08 +03:00
committed by Nikita Iarychenko
parent 083dfc6a59
commit 92d85cab3c
15 changed files with 1245 additions and 37 deletions

460
.idea/dbnavigator.xml generated Normal file
View File

@@ -0,0 +1,460 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DBNavigator.Project.DDLFileAttachmentManager">
<mappings />
<preferences />
</component>
<component name="DBNavigator.Project.DatabaseAssistantManager">
<assistants />
<selection-state>
<model-selection />
</selection-state>
</component>
<component name="DBNavigator.Project.DatabaseBrowserManager">
<autoscroll-to-editor value="false" />
<autoscroll-from-editor value="true" />
<show-object-properties value="true" />
<loaded-nodes />
</component>
<component name="DBNavigator.Project.DatabaseFileManager">
<open-files />
</component>
<component name="DBNavigator.Project.ExecutionManager">
<retain-sticky-names value="false" />
</component>
<component name="DBNavigator.Project.Settings">
<connections />
<browser-settings>
<general>
<display-mode value="TABBED" />
<navigation-history-size value="100" />
<show-object-details value="false" />
<enable-sticky-paths value="true" />
<enable-quick-filters value="false" />
</general>
<filters>
<object-type-filter>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="true" />
<object-type name="ROLE" enabled="true" />
<object-type name="PRIVILEGE" enabled="true" />
<object-type name="CHARSET" enabled="true" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="JSON_VIEW" enabled="true" />
<object-type name="MATERIALIZED_VIEW" enabled="true" />
<object-type name="NESTED_TABLE" enabled="true" />
<object-type name="COLUMN" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET_TRIGGER" enabled="true" />
<object-type name="DATABASE_TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="true" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
<object-type name="ARGUMENT" enabled="true" />
<object-type name="JAVA_CLASS" enabled="true" />
<object-type name="JAVA_FIELD" enabled="true" />
<object-type name="JAVA_METHOD" enabled="true" />
<object-type name="JAVA_RESOURCE" enabled="true" />
<object-type name="DIMENSION" enabled="true" />
<object-type name="CLUSTER" enabled="true" />
<object-type name="DBLINK" enabled="true" />
<object-type name="CREDENTIAL" enabled="true" />
<object-type name="AI_PROFILE" enabled="true" />
<object-type name="AI_MODEL" enabled="true" />
</object-type-filter>
</filters>
<sorting>
<object-type name="COLUMN" sorting-type="NAME" />
<object-type name="FUNCTION" sorting-type="NAME" />
<object-type name="PROCEDURE" sorting-type="NAME" />
<object-type name="ARGUMENT" sorting-type="POSITION" />
<object-type name="TYPE ATTRIBUTE" sorting-type="POSITION" />
</sorting>
<default-editors>
<object-type name="VIEW" editor-type="SELECTION" />
<object-type name="PACKAGE" editor-type="SELECTION" />
<object-type name="TYPE" editor-type="SELECTION" />
</default-editors>
</browser-settings>
<navigation-settings>
<lookup-filters>
<lookup-objects>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="false" />
<object-type name="ROLE" enabled="false" />
<object-type name="PRIVILEGE" enabled="false" />
<object-type name="CHARSET" enabled="false" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="JSON VIEW" enabled="true" />
<object-type name="MATERIALIZED VIEW" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET TRIGGER" enabled="true" />
<object-type name="DATABASE TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="false" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="JAVA CLASS" enabled="true" />
<object-type name="INNER CLASS" enabled="true" />
<object-type name="JAVA FIELD" enabled="true" />
<object-type name="JAVA METHOD" enabled="true" />
<object-type name="JAVA PARAMETER" enabled="true" />
<object-type name="JAVA RESOURCE" enabled="true" />
<object-type name="DIMENSION" enabled="false" />
<object-type name="CLUSTER" enabled="false" />
<object-type name="DBLINK" enabled="false" />
<object-type name="CREDENTIAL" enabled="false" />
</lookup-objects>
<force-database-load value="false" />
<prompt-connection-selection value="true" />
<prompt-schema-selection value="true" />
</lookup-filters>
</navigation-settings>
<dataset-grid-settings>
<general>
<enable-zooming value="true" />
<enable-column-tooltip value="true" />
</general>
<sorting>
<nulls-first value="true" />
<max-sorting-columns value="4" />
</sorting>
<audit-columns>
<column-names value="" />
<visible value="true" />
<editable value="false" />
</audit-columns>
</dataset-grid-settings>
<dataset-editor-settings>
<text-editor-popup>
<active value="false" />
<active-if-empty value="false" />
<data-length-threshold value="100" />
<popup-delay value="1000" />
</text-editor-popup>
<values-actions-popup>
<show-popup-button value="true" />
<element-count-threshold value="1000" />
<data-length-threshold value="250" />
</values-actions-popup>
<general>
<fetch-block-size value="100" />
<fetch-timeout value="30" />
<trim-whitespaces value="true" />
<convert-empty-strings-to-null value="true" />
<select-content-on-cell-edit value="true" />
<large-value-preview-active value="true" />
</general>
<filters>
<prompt-filter-dialog value="true" />
<default-filter-type value="BASIC" />
</filters>
<qualified-text-editor text-length-threshold="300">
<content-types>
<content-type name="Text" enabled="true" />
<content-type name="Properties" enabled="true" />
<content-type name="XML" enabled="true" />
<content-type name="DTD" enabled="true" />
<content-type name="HTML" enabled="true" />
<content-type name="XHTML" enabled="true" />
<content-type name="Java" enabled="true" />
<content-type name="SQL" enabled="true" />
<content-type name="PL/SQL" enabled="true" />
<content-type name="JSON" enabled="true" />
<content-type name="JSON5" enabled="true" />
<content-type name="Groovy" enabled="true" />
<content-type name="YAML" enabled="true" />
<content-type name="Manifest" enabled="true" />
</content-types>
</qualified-text-editor>
<record-navigation>
<navigation-target value="VIEWER" />
</record-navigation>
</dataset-editor-settings>
<code-editor-settings>
<general>
<show-object-navigation-gutter value="false" />
<show-spec-declaration-navigation-gutter value="true" />
<enable-spellchecking value="true" />
<enable-reference-spellchecking value="false" />
</general>
<confirmations>
<save-changes value="false" />
<revert-changes value="true" />
<exit-on-changes value="ASK" />
</confirmations>
</code-editor-settings>
<code-completion-settings>
<filters>
<basic-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="json view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="false" />
<filter-element type="OBJECT" id="view" selected="false" />
<filter-element type="OBJECT" id="json view" selected="false" />
<filter-element type="OBJECT" id="materialized view" selected="false" />
<filter-element type="OBJECT" id="index" selected="false" />
<filter-element type="OBJECT" id="constraint" selected="false" />
<filter-element type="OBJECT" id="trigger" selected="false" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="false" />
<filter-element type="OBJECT" id="procedure" selected="false" />
<filter-element type="OBJECT" id="function" selected="false" />
<filter-element type="OBJECT" id="package" selected="false" />
<filter-element type="OBJECT" id="type" selected="false" />
<filter-element type="OBJECT" id="dimension" selected="false" />
<filter-element type="OBJECT" id="cluster" selected="false" />
<filter-element type="OBJECT" id="dblink" selected="false" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="json view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</basic-filter>
<extended-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="json view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="json view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="json view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</extended-filter>
</filters>
<sorting enabled="true">
<sorting-element type="RESERVED_WORD" id="keyword" />
<sorting-element type="RESERVED_WORD" id="datatype" />
<sorting-element type="OBJECT" id="column" />
<sorting-element type="OBJECT" id="table" />
<sorting-element type="OBJECT" id="view" />
<sorting-element type="OBJECT" id="json view" />
<sorting-element type="OBJECT" id="materialized view" />
<sorting-element type="OBJECT" id="index" />
<sorting-element type="OBJECT" id="constraint" />
<sorting-element type="OBJECT" id="trigger" />
<sorting-element type="OBJECT" id="synonym" />
<sorting-element type="OBJECT" id="sequence" />
<sorting-element type="OBJECT" id="procedure" />
<sorting-element type="OBJECT" id="function" />
<sorting-element type="OBJECT" id="package" />
<sorting-element type="OBJECT" id="type" />
<sorting-element type="OBJECT" id="dimension" />
<sorting-element type="OBJECT" id="cluster" />
<sorting-element type="OBJECT" id="dblink" />
<sorting-element type="OBJECT" id="schema" />
<sorting-element type="OBJECT" id="role" />
<sorting-element type="OBJECT" id="user" />
<sorting-element type="RESERVED_WORD" id="function" />
<sorting-element type="RESERVED_WORD" id="parameter" />
</sorting>
<format>
<enforce-code-style-case value="true" />
</format>
</code-completion-settings>
<execution-engine-settings>
<statement-execution>
<fetch-block-size value="100" />
<execution-timeout value="20" />
<debug-execution-timeout value="600" />
<focus-result value="false" />
<prompt-execution value="false" />
</statement-execution>
<script-execution>
<command-line-interfaces />
<execution-timeout value="300" />
</script-execution>
<method-execution>
<execution-timeout value="30" />
<debug-execution-timeout value="600" />
<parameter-history-size value="10" />
</method-execution>
<method-execution>
<execution-timeout value="30" />
<debug-execution-timeout value="600" />
<parameter-history-size value="10" />
</method-execution>
</execution-engine-settings>
<operation-settings>
<transactions>
<uncommitted-changes>
<on-project-close value="ASK" />
<on-disconnect value="ASK" />
<on-autocommit-toggle value="ASK" />
</uncommitted-changes>
<multiple-uncommitted-changes>
<on-commit value="ASK" />
<on-rollback value="ASK" />
</multiple-uncommitted-changes>
</transactions>
<session-browser>
<disconnect-session value="ASK" />
<kill-session value="ASK" />
<reload-on-filter-change value="false" />
</session-browser>
<compiler>
<compile-type value="KEEP" />
<compile-dependencies value="ASK" />
<always-show-controls value="false" />
</compiler>
</operation-settings>
<ddl-file-settings>
<extensions>
<mapping file-type-id="VIEW" extensions="vw" />
<mapping file-type-id="TRIGGER" extensions="trg" />
<mapping file-type-id="PROCEDURE" extensions="prc" />
<mapping file-type-id="FUNCTION" extensions="fnc" />
<mapping file-type-id="PACKAGE" extensions="pkg" />
<mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
<mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
<mapping file-type-id="TYPE" extensions="tpe" />
<mapping file-type-id="TYPE_SPEC" extensions="tps" />
<mapping file-type-id="TYPE_BODY" extensions="tpb" />
<mapping file-type-id="JAVA_SOURCE" extensions="sql" />
</extensions>
<general>
<lookup-ddl-files value="true" />
<create-ddl-files value="false" />
<synchronize-ddl-files value="true" />
<use-qualified-names value="false" />
<make-scripts-rerunnable value="true" />
</general>
</ddl-file-settings>
<assistant-settings>
<credential-settings>
<credentials />
</credential-settings>
<profile-settings>
<profiles />
</profile-settings>
</assistant-settings>
<general-settings>
<regional-settings>
<date-format value="MEDIUM" />
<number-format value="UNGROUPED" />
<locale value="SYSTEM_DEFAULT" />
<use-custom-formats value="false" />
</regional-settings>
<environment>
<environment-types>
<environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
<environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
<environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
<environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
</environment-types>
<visibility-settings>
<connection-tabs value="true" />
<dialog-headers value="true" />
<object-editor-tabs value="true" />
<script-editor-tabs value="false" />
<execution-result-tabs value="true" />
</visibility-settings>
</environment>
</general-settings>
</component>
</project>

View File

@@ -67,5 +67,6 @@
<orderEntry type="module" module-name="intellij.platform.ide.ui" />
<orderEntry type="module" module-name="intellij.platform.ide.initialConfigImport" />
<orderEntry type="module" module-name="intellij.platform.plugins.parser.impl" />
<orderEntry type="module" module-name="intellij.java.ui" />
</component>
</module>

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 60 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M59.024 19.4576C57.5531 18.4675 53.6878 18.0446 50.8776 18.8015C50.7261 16.0024 49.2829 13.6437 46.6426 11.5857L45.6651 10.9296L45.0138 11.9134C43.7333 13.8571 43.1938 16.4467 43.385 18.8007C43.5357 20.251 44.0403 21.8814 45.0138 23.0643C41.3563 25.1858 37.9852 24.7042 23.0555 24.7042H0.00465616C-0.062781 28.0753 0.479096 34.5603 4.60307 39.8395C5.05847 40.4226 5.5583 40.9867 6.10018 41.5302C9.45299 44.8877 14.5187 47.3496 22.0939 47.3567C33.6502 47.367 43.5516 41.1208 49.5741 26.0172C51.556 26.0498 56.7875 26.3727 59.3477 21.4252C59.4104 21.3419 59.9991 20.1129 59.9991 20.1129L59.0232 19.4568L59.024 19.4576ZM15.0479 16.3745H8.566V22.8564H15.0479V16.3745ZM23.422 16.3745H16.9401V22.8564H23.422V16.3745ZM31.7961 16.3745H25.3142V22.8564H31.7961V16.3745ZM40.1702 16.3745H33.6883V22.8564H40.1702V16.3745ZM6.67379 16.3745H0.191893V22.8564H6.67379V16.3745ZM15.0479 8.18766H8.566V14.6696H15.0479V8.18766ZM23.422 8.18766H16.9401V14.6696H23.422V8.18766ZM31.7961 8.18766H25.3142V14.6696H31.7961V8.18766ZM31.7961 0H25.3142V6.4819H31.7961V0Z" fill="#1D63ED"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -29,7 +29,7 @@
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceInterface="com.intellij.ide.startup.importSettings.data.StartupWizardService"
serviceImplementation="com.intellij.ide.startup.importSettings.data.DisabledStartupWizardPages"/>
serviceImplementation="com.intellij.ide.startup.importSettings.chooser.ui.OpenIdeStartupWizardService"/>
<transferSettings.thirdPartyProductSettingsTransfer id="VSCodeSettingsTransfer"
implementation="com.intellij.ide.startup.importSettings.transfer.VsCodeSettingsTransfer"/>

View File

@@ -87,13 +87,36 @@ choose.product.setting.sync.turned.off=Setting Sync Is Turned Off
choose.keymap.title = Choose Keymap
wizard.button.continue = Continue
plugins.page.title = Featured Plugins
plugins.page.ok.button.continue.without = Continue without Plugins
plugins.page.ok.button.install = Install Selected
plugins.page.choose.counter.no = No plugins selected for installation
plugins.page.choose.counter.one = 1 plugin selected for installation
plugins.page.choose.counter.multiple = {0} plugins selected for installation
install.plugins.page.title = Installing Plugins\u2026
plugins.page.title = Рекомендуемые Плагины
plugins.page.ok.button.continue.without = Продолжить без Плагинов
plugins.page.ok.button.install = Установить Выбранные
plugins.page.choose.counter.no = Нет плагинов для установки
plugins.page.choose.counter.one = 1 плагин выбран для установки
plugins.page.choose.counter.multiple = {0} плагина выбрано для установки
plugins.page.list.item.bundled = Предустановлен
# Plugin descriptions
plugin.description.mapstruct = Плагин для редактирования MapStruct мапперов
plugin.description.init.spring = Интеграция Init Spring для новых проектов
plugin.description.checkStyle = Статический анализ кода на соответствие стандартам кодирования
plugin.description.mavenHelper = Анализ зависимостей Maven и запуск из редактора
plugin.description.java.kotlin.support = Поддерживается OpenIDE
plugin.description.spring.support = Поддерживается Amplicode
plugin.description.python = Поддержка языка Python
plugin.description.django = Поддержка Django фреймворка для веб-приложений на Python
plugin.description.pylint = Статический анализатор кода Python для выявления ошибок
plugin.description.csvEditor = Редактор CSV и TSV файлов с подсветкой и форматированием
plugin.description.pydantic = Поддержка Pydantic для валидации данных в Python
plugin.description.webtools = Набор инструментов для веб-разработки
plugin.description.go = Поддержка языка Go
plugin.description.fileWatchers = Автоматический запуск внешних инструментов при изменении файлов
plugin.description.makefile = Подсветка синтаксиса и навигация для Makefile
plugin.description.protocolBuffers = Поддержка Protocol Buffers для сериализации данных
plugin.description.kilocode = Kilo Code AI Агент
plugin.description.continue = Open-source AI ассистент для кода
plugin.description.docker = Поддержка Docker для управления контейнерами
install.plugins.page.title = Установка Плагинов\u2026
theme.page.title = Choose Theme
theme.page.dark = Dark

View File

@@ -0,0 +1,29 @@
// OpenIDE Project
// Copyright (C) 2026 “Open Development Platform” Ltd. (https://openide.ru)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3 or later as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
package com.intellij.ide.startup.importSettings;
import com.intellij.ui.IconManager;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public final class OpenIdePluginIcons {
private static @NotNull Icon load(@NotNull String path, int cacheKey, int flags) {
return IconManager.getInstance().loadRasterizedIcon(path, OpenIdePluginIcons.class.getClassLoader(), cacheKey, flags);
}
public static final class Icons {
/** 60x48 */ public static final @NotNull Icon Docker = load("icons/docker.svg", -271658419, 0);
}
}

View File

@@ -1,4 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
// Modified by Artyom Orlov at 2026 as part of the OpenIDE project(https://openide.ru).
// Any modifications are available on the same license terms as the original source code.
package com.intellij.ide.startup.importSettings.chooser.ui
import com.intellij.ide.startup.importSettings.data.StartupWizardService
@@ -107,7 +110,7 @@ class OnboardingController private constructor(){
}
service.onEnter()
wizardController.goToThemePage(true)
wizardController.goToPluginPage()
if(!dl.isShowing) {
dl.initialize()

View File

@@ -0,0 +1,239 @@
// OpenIDE Project
// Copyright (C) 2026 “Open Development Platform” Ltd. (https://openide.ru)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3 or later as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
package com.intellij.ide.startup.importSettings.chooser.ui
import com.intellij.icons.AllIcons
import com.intellij.ide.startup.importSettings.ImportSettingsBundle
import com.intellij.ide.startup.importSettings.OpenIdePluginIcons
import com.intellij.ide.startup.importSettings.StartupImportIcons
import com.intellij.ide.startup.importSettings.data.*
import com.intellij.java.ui.icons.JavaUIIcons
import com.jetbrains.rd.util.lifetime.Lifetime
import com.jetbrains.rd.util.reactive.IVoidSource
import com.jetbrains.rd.util.reactive.OptProperty
import com.jetbrains.rd.util.reactive.Property
class OpenIdeStartupWizardService : StartupWizardService {
override val isActive = true
override val shouldClose: IVoidSource
get() = object : IVoidSource {
override fun advise(lifetime: Lifetime, handler: (Unit) -> Unit) {
}
}
override fun getKeymapService(): KeymapService {
TODO("Not yet implemented")
}
override fun getThemeService(): ThemeService {
TODO("Not yet implemented")
}
override fun getPluginService(): PluginService {
return object : PluginService {
override val pluginGroups: List<WizardPluginGroup>
get() = listOf(
WizardPluginGroupImpl(
id = "java-kotlin",
name = "Java / Kotlin",
icon = AllIcons.FileTypes.Java,
plugins = listOf(
WizardPluginImpl(
id = "org.mapstruct.intellij",
icon = AllIcons.Plugins.PluginLogo,
name = "MapStruct Support",
description = ImportSettingsBundle.message("plugin.description.mapstruct"),
),
WizardPluginImpl(
id = "pro.nikolaev.init-spring",
icon = AllIcons.Plugins.PluginLogo,
name = "Init Spring",
description = ImportSettingsBundle.message("plugin.description.init.spring"),
),
WizardPluginImpl(
id = "CheckStyle-IDEA",
icon = AllIcons.Plugins.PluginLogo,
name = "CheckStyle-IDEA",
description = ImportSettingsBundle.message("plugin.description.checkStyle"),
),
WizardPluginImpl(
id = "MavenRunHelper",
icon = AllIcons.Plugins.PluginLogo,
name = "Maven Helper",
description = ImportSettingsBundle.message("plugin.description.mavenHelper"),
),
WizardPluginImpl(
id = "bundled.java.kotlin",
icon = AllIcons.FileTypes.Java,
name = "Java / Kotlin support",
description = ImportSettingsBundle.message("plugin.description.java.kotlin.support"),
bundled = true,
),
WizardPluginImpl(
id = "bundled.spring",
icon = JavaUIIcons.SpringPromo,
name = "Spring support",
description = ImportSettingsBundle.message("plugin.description.spring.support"),
bundled = true,
),
)
),
WizardPluginGroupImpl(
id = "python",
name = "Python",
icon = AllIcons.Language.Python,
plugins = listOf(
WizardPluginImpl(
id = "PythonCore",
icon = AllIcons.Plugins.PluginLogo,
name = "Python Community Edition",
description = ImportSettingsBundle.message("plugin.description.python"),
),
WizardPluginImpl(
id = "com.haulmont.django",
icon = AllIcons.Plugins.PluginLogo,
name = "Django[beta]",
description = ImportSettingsBundle.message("plugin.description.django"),
),
WizardPluginImpl(
id = "com.leinardi.pycharm.pylint",
icon = AllIcons.Plugins.PluginLogo,
name = "Pylint",
description = ImportSettingsBundle.message("plugin.description.pylint"),
),
WizardPluginImpl(
id = "net.seesharpsoft.intellij.plugins.csv",
icon = AllIcons.Plugins.PluginLogo,
name = "CSV Editor",
description = ImportSettingsBundle.message("plugin.description.csvEditor"),
),
WizardPluginImpl(
id = "com.koxudaxi.pydantic",
icon = AllIcons.Plugins.PluginLogo,
name = "Pydantic",
description = ImportSettingsBundle.message("plugin.description.pydantic"),
),
)
),
WizardPluginGroupImpl(
id = "web",
name = "Web",
icon = AllIcons.FileTypes.Html,
plugins = listOf(
WizardPluginImpl(
id = "com.haulmont.webtools",
icon = AllIcons.Plugins.PluginLogo,
name = "Frontend/Web [beta]",
description = ImportSettingsBundle.message("plugin.description.webtools"),
),
)
),
WizardPluginGroupImpl(
id = "go",
name = "Go",
icon = AllIcons.Language.GO,
plugins = listOf(
WizardPluginImpl(
id = "org.jetbrains.plugins.go",
icon = AllIcons.Plugins.PluginLogo,
name = "Go [beta]",
description = ImportSettingsBundle.message("plugin.description.go"),
),
WizardPluginImpl(
id = "com.intellij.plugins.watcher",
icon = AllIcons.Plugins.PluginLogo,
name = "File Watchers",
description = ImportSettingsBundle.message("plugin.description.fileWatchers"),
),
WizardPluginImpl(
id = "name.kropp.intellij.makefile",
icon = AllIcons.Plugins.PluginLogo,
name = "Makefile Language",
description = ImportSettingsBundle.message("plugin.description.makefile"),
),
WizardPluginImpl(
id = "idea.plugin.protoeditor",
icon = AllIcons.Plugins.PluginLogo,
name = "Protocol Buffers",
description = ImportSettingsBundle.message("plugin.description.protocolBuffers"),
),
)
),
WizardPluginGroupImpl(
id = "ai",
name = "AI",
icon = AllIcons.Actions.Lightning,
plugins = listOf(
WizardPluginImpl(
id = "ai.kilocode.jetbrains",
icon = AllIcons.Plugins.PluginLogo,
name = "Kilo Code",
description = ImportSettingsBundle.message("plugin.description.kilocode"),
),
WizardPluginImpl(
id = "com.github.continuedev.continueintellijextension",
icon = AllIcons.Plugins.PluginLogo,
name = "Continue",
description = ImportSettingsBundle.message("plugin.description.continue"),
),
)
),
WizardPluginGroupImpl(
id = "deployment",
name = "Deployment",
icon = OpenIdePluginIcons.Icons.Docker,
plugins = listOf(
WizardPluginImpl(
id = "ru.openide.docker",
icon = AllIcons.Plugins.PluginLogo,
name = "Docker",
description = ImportSettingsBundle.message("plugin.description.docker"),
),
)
),
)
override fun onStepEnter() {
}
override fun install(lifetime: Lifetime, ids: List<String>): PluginImportProgress {
return object : PluginImportProgress {
override val icon = Property(AllIcons.Plugins.PluginLogo)
override val progressMessage = Property(null)
override val progress = OptProperty<Int>()
}
}
override fun skipPlugins() {
}
override fun shouldShowPage(pluginIdsMarkedForInstallation: List<String>): Boolean {
return true
}
}
}
override fun onEnter() {
}
override fun onCancel() {
}
override fun onExit() {
}
}

View File

@@ -1,4 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
// Modified by Artyom Orlov at 2026 as part of the OpenIDE project(https://openide.ru).
// Any modifications are available on the same license terms as the original source code.
package com.intellij.ide.startup.importSettings.chooser.ui
import com.intellij.ide.startup.importSettings.data.StartupWizardService
@@ -64,9 +67,8 @@ internal class WizardControllerImpl(dialog: OnboardingDialog,
}
override fun goToPluginPage() {
val page = WizardPluginsPage(this, service.getPluginService(), goBackAction = {
goToKeymapPage(isForwardDirection = false)
}, goForwardAction = { ids ->
val page = WizardPluginsPage(this, service.getPluginService(), goBackAction = null,
goForwardAction = { ids ->
goToInstallPluginPage(ids)
}, continueButtonTextOverride = null)
dialog.changePage(page)

View File

@@ -1,4 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
// Modified by Artyom Orlov at 2026 as part of the OpenIDE project(https://openide.ru).
// Any modifications are available on the same license terms as the original source code.
package com.intellij.ide.startup.importSettings.data
import com.intellij.ide.startup.importSettings.ImportSettingsBundle
@@ -87,7 +90,7 @@ data class WizardScheme(
)
interface PluginService {
val plugins: List<WizardPlugin>
val pluginGroups: List<WizardPluginGroup>
fun onStepEnter()
fun install(lifetime: Lifetime, ids: List<String>): PluginImportProgress
fun skipPlugins()
@@ -103,6 +106,15 @@ interface WizardPlugin {
val icon: Icon
val name: String
val description: String?
val bundled: Boolean
get() = false
}
interface WizardPluginGroup {
val id: String
val name: String
val icon: Icon
val plugins: List<WizardPlugin>
}
interface KeymapService {

View File

@@ -1,4 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
// Modified by Artyom Orlov at 2026 as part of the OpenIDE project(https://openide.ru).
// Any modifications are available on the same license terms as the original source code.
package com.intellij.ide.startup.importSettings.data
import com.intellij.icons.AllIcons
@@ -113,7 +116,14 @@ class PluginServiceImpl : PluginService {
)
override val plugins: List<WizardPlugin> = listOf
override val pluginGroups: List<WizardPluginGroup> = listOf(
WizardPluginGroupImpl(
id = "mock.group",
name = "Mock Group",
icon = AllIcons.Plugins.PluginLogo,
plugins = listOf
)
)
override fun onStepEnter() {}
@@ -154,8 +164,15 @@ class TestPluginImportProgress(lifetime: Lifetime) : TestImportProgress(lifetime
class WizardPluginImpl(override val icon: Icon,
override val name: String,
override val description: String? = null,
override val id: String = UUID.randomUUID().toString()) : WizardPlugin {
}
override val id: String = UUID.randomUUID().toString(),
override val bundled: Boolean = false) : WizardPlugin
class WizardPluginGroupImpl(
override val id: String,
override val name: String,
override val icon: Icon,
override val plugins: List<WizardPlugin>
) : WizardPluginGroup
@Suppress("HardCodedStringLiteral")
class TestKeymapService : KeymapService {

View File

@@ -0,0 +1,53 @@
// OpenIDE Project
// Copyright (C) 2026 “Open Development Platform” Ltd. (https://openide.ru)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3 or later as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
package com.intellij.ide.startup.importSettings.openide.service
import com.intellij.ide.plugins.marketplace.MarketplaceRequests
import com.intellij.ide.plugins.newui.PluginLogo
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.util.IntellijInternalApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.swing.Icon
@Service(Service.Level.APP)
class PluginIconService {
suspend fun loadIcon(pluginId: String): Icon? {
return withContext(Dispatchers.IO) {
loadFromMarketplace(pluginId)
}
}
@OptIn(IntellijInternalApi::class)
private fun loadFromMarketplace(pluginId: String): Icon? {
return try {
val marketplaceRequests = MarketplaceRequests.getInstance()
val pluginNode = marketplaceRequests.getLastCompatiblePluginUpdateModel(
PluginId.getId(pluginId),
buildNumber = null
) ?: return null
PluginLogo.getIcon(pluginNode.getDescriptor(), false, false, false)
} catch (_: Exception) {
null
}
}
companion object {
fun getInstance(): PluginIconService = service()
}
}

View File

@@ -0,0 +1,173 @@
// OpenIDE Project
// Copyright (C) 2026 “Open Development Platform” Ltd. (https://openide.ru)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3 or later as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
package com.intellij.ide.startup.importSettings.wizard.pluginChooser
import com.intellij.icons.AllIcons
import com.intellij.ide.startup.importSettings.data.WizardPluginGroup
import com.intellij.ui.components.JBLabel
import com.intellij.ui.components.panels.VerticalLayout
import com.intellij.util.IconUtil
import com.intellij.util.ui.JBFont
import com.intellij.util.ui.JBUI
import com.intellij.util.ui.ThreeStateCheckBox
import com.intellij.util.ui.UIUtil
import java.awt.BorderLayout
import java.awt.Cursor
import java.awt.FlowLayout
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import kotlinx.coroutines.CoroutineScope
import javax.swing.Icon
import javax.swing.JLabel
import javax.swing.JPanel
class OpenIdeWizardPluginGroupPane(
private val group: WizardPluginGroup,
private val coroutineScope: CoroutineScope,
private val onSelectionChanged: () -> Unit
) {
private val pluginPanes = mutableListOf<OpenIdeWizardPluginPane>()
private val groupCheckbox = ThreeStateCheckBox()
private val counterLabel = JLabel()
private val contentPanel = JPanel(VerticalLayout(0)).apply {
isOpaque = false
isVisible = false
border = JBUI.Borders.emptyLeft(28)
group.plugins.forEach { plugin ->
val pluginPane = OpenIdeWizardPluginPane(plugin, coroutineScope) {
updateGroupCheckboxState()
onSelectionChanged()
}
pluginPanes.add(pluginPane)
add(pluginPane.pane)
}
}
private val expandIcon = JLabel()
private var isExpanded = false
val pane: JPanel = createPane()
private val selectablePanes: List<OpenIdeWizardPluginPane>
get() = pluginPanes.filter { !it.isBundled }
val selectedPlugins: List<OpenIdeWizardPluginPane>
get() = pluginPanes.filter { it.selected && !it.isBundled }
val selectedCount: Int
get() = selectablePanes.count { it.selected }
val totalCount: Int
get() = selectablePanes.size
private fun createPane(): JPanel {
return JPanel(BorderLayout()).apply {
isOpaque = false
border = JBUI.Borders.empty(0, 16)
add(createHeader(), BorderLayout.NORTH)
add(contentPanel, BorderLayout.CENTER)
updateGroupCheckboxState()
}
}
private fun createHeader(): JPanel {
groupCheckbox.apply {
isOpaque = false
isThirdStateEnabled = false
addActionListener {
val shouldSelect = state == ThreeStateCheckBox.State.SELECTED
selectablePanes.forEach { it.setSelected(shouldSelect) }
updateGroupCheckboxState()
onSelectionChanged()
}
}
counterLabel.apply {
foreground = UIUtil.getContextHelpForeground()
font = JBFont.label()
}
expandIcon.apply {
icon = getExpandIcon()
cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
toggleExpanded()
}
})
}
val scaledIcon = IconUtil.scale(group.icon, null, 1.5f)
val groupIcon = JLabel(scaledIcon).apply {
border = JBUI.Borders.emptyRight(8)
}
val groupName = JBLabel(group.name).apply {
font = JBFont.h4()
}
val headerClickArea = JPanel(FlowLayout(FlowLayout.LEFT, 0, 0)).apply {
isOpaque = false
add(expandIcon)
add(groupCheckbox)
add(groupIcon)
add(groupName)
add(JLabel(" ").apply { border = JBUI.Borders.emptyLeft(4) })
add(counterLabel)
cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
if (e.source !== expandIcon && e.source !== groupCheckbox) {
toggleExpanded()
}
}
})
}
return JPanel(BorderLayout()).apply {
isOpaque = false
border = JBUI.Borders.empty(4, 0)
add(headerClickArea, BorderLayout.CENTER)
}
}
private fun updateGroupCheckboxState() {
val selectable = selectablePanes
val selectedCount = selectable.count { it.selected }
groupCheckbox.state = when (selectedCount) {
0 -> ThreeStateCheckBox.State.NOT_SELECTED
selectable.size -> ThreeStateCheckBox.State.SELECTED
else -> ThreeStateCheckBox.State.DONT_CARE
}
counterLabel.text = "($selectedCount/${selectable.size})"
}
private fun toggleExpanded() {
isExpanded = !isExpanded
contentPanel.isVisible = isExpanded
expandIcon.icon = getExpandIcon()
}
private fun getExpandIcon(): Icon {
return if (isExpanded) AllIcons.General.ArrowDown else AllIcons.General.ArrowRight
}
fun setAllSelected(selected: Boolean) {
selectablePanes.forEach { it.setSelected(selected) }
updateGroupCheckboxState()
}
}

View File

@@ -0,0 +1,173 @@
// OpenIDE Project
// Copyright (C) 2026 “Open Development Platform” Ltd. (https://openide.ru)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3 or later as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
package com.intellij.ide.startup.importSettings.wizard.pluginChooser
import com.intellij.ide.startup.importSettings.ImportSettingsBundle
import com.intellij.ide.startup.importSettings.data.WizardPlugin
import com.intellij.ide.startup.importSettings.openide.service.PluginIconService
import com.intellij.ui.components.JBCheckBox
import com.intellij.ui.dsl.builder.HyperlinkEventAction
import com.intellij.ui.dsl.builder.MAX_LINE_LENGTH_WORD_WRAP
import com.intellij.ui.dsl.builder.components.DslLabel
import com.intellij.ui.dsl.builder.components.DslLabelType
import com.intellij.util.IconUtil
import com.intellij.util.ui.JBUI
import com.intellij.util.ui.UIUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.awt.GridBagConstraints
import java.awt.GridBagLayout
import javax.swing.JEditorPane
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.SwingUtilities
class OpenIdeWizardPluginPane(val plugin: WizardPlugin, private val coroutineScope: CoroutineScope, changeHandler: () -> Unit) {
private var checkBox = JBCheckBox().apply {
isOpaque = false
}
val selected: Boolean
get() = checkBox.isSelected
fun setSelected(value: Boolean) {
checkBox.isSelected = value
}
fun setEnabled(value: Boolean) {
checkBox.isEnabled = value
pane.isEnabled = value
nameLabel.isEnabled = value
}
private val iconLabel = JLabel(IconUtil.resizeSquared(plugin.icon, 24))
private val nameLabel = createLabel()
private val bundledLabel = JLabel(ImportSettingsBundle.message("plugins.page.list.item.bundled")).apply {
foreground = UIUtil.getContextHelpForeground()
border = JBUI.Borders.emptyRight(10)
}
val pane = JPanel(GridBagLayout()).apply {
val c = GridBagConstraints()
plugin.description?.let {
c.gridx = 0
c.gridy = 0
c.weightx = 0.0
c.anchor = GridBagConstraints.CENTER
add(checkBox, c)
c.gridx = 1
c.anchor = GridBagConstraints.CENTER
add(iconLabel.apply {
border = JBUI.Borders.empty(0, 10)
}, c)
c.gridx = 2
c.weightx = 1.0
c.fill = GridBagConstraints.HORIZONTAL
add(JPanel(GridBagLayout()).apply {
isOpaque = false
val inner = GridBagConstraints()
inner.gridx = 0
inner.gridy = 0
inner.weightx = 1.0
inner.fill = GridBagConstraints.HORIZONTAL
inner.anchor = GridBagConstraints.WEST
add(nameLabel.apply {
text = plugin.name
}, inner)
inner.gridy = 1
add(createLabel().apply {
text = plugin.description
foreground = UIUtil.getLabelDisabledForeground()
}, inner)
}, c)
if (plugin.bundled) {
c.gridx = 3
c.weightx = 0.0
c.fill = GridBagConstraints.NONE
c.anchor = GridBagConstraints.EAST
add(bundledLabel, c)
}
} ?: run {
c.gridx = 0
c.gridy = 0
c.weightx = 0.0
add(checkBox, c)
c.gridx = 1
c.gridy = 0
add(iconLabel.apply {
border = JBUI.Borders.empty(0, 10)
}, c)
c.gridx = 2
c.gridy = 0
c.weightx = 1.0
c.fill = GridBagConstraints.HORIZONTAL
add(nameLabel.apply {
text = plugin.name
}, c)
if (plugin.bundled) {
c.gridx = 3
c.weightx = 0.0
c.fill = GridBagConstraints.NONE
c.anchor = GridBagConstraints.EAST
add(bundledLabel, c)
}
}
}.apply {
isOpaque = false
border = JBUI.Borders.empty(8, 20)
}
val isBundled: Boolean = plugin.bundled
init {
loadIconAsync()
if (isBundled) {
checkBox.isSelected = true
setEnabled(false)
}
checkBox.addItemListener {
changeHandler()
}
}
private fun createLabel(): JEditorPane {
val dslLabel = DslLabel(DslLabelType.LABEL)
dslLabel.action = HyperlinkEventAction.HTML_HYPERLINK_INSTANCE
dslLabel.maxLineLength = MAX_LINE_LENGTH_WORD_WRAP
return dslLabel
}
private fun loadIconAsync() {
coroutineScope.launch {
val icon = PluginIconService.getInstance().loadIcon(plugin.id)
if (icon != null) {
SwingUtilities.invokeLater {
iconLabel.icon = IconUtil.resizeSquared(icon, 24)
pane.repaint()
}
}
}
}
}

View File

@@ -1,9 +1,13 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
// Modified by Artyom Orlov at 2026 as part of the OpenIDE project(https://openide.ru).
// Any modifications are available on the same license terms as the original source code.
package com.intellij.ide.startup.importSettings.wizard.pluginChooser
import com.intellij.ide.startup.importSettings.ImportSettingsBundle
import com.intellij.ide.startup.importSettings.chooser.ui.*
import com.intellij.ide.startup.importSettings.data.PluginService
import com.intellij.ide.startup.importSettings.data.WizardPluginGroup
import com.intellij.openapi.util.NlsActions.ActionText
import com.intellij.openapi.util.SystemInfo
import com.intellij.platform.ide.bootstrap.StartupWizardStage
@@ -20,14 +24,14 @@ import javax.swing.*
internal class WizardPluginsPage(
val controller: BaseController,
private val pluginService: PluginService,
goBackAction: () -> Unit,
goBackAction: (() -> Unit)?,
goForwardAction: (List<String>) -> Unit,
private val continueButtonTextOverride: @ActionText String?
) : OnboardingPage {
override val stage: StartupWizardStage = StartupWizardStage.WizardPluginPage
private val pluginPanes = mutableListOf<WizardPluginPane>()
private val groupPanes = mutableListOf<OpenIdeWizardPluginGroupPane>()
private val contentPage: JComponent
@@ -35,14 +39,20 @@ internal class WizardPluginsPage(
border = JBUI.Borders.emptyLeft(26)
foreground = UIUtil.getContextHelpForeground()
}
override fun confirmExit(parentComponent: Component?): Boolean = true
private fun getSelected(): List<WizardPluginPane> {
return pluginPanes.filter { it.selected }.toList()
private fun getSelected(): List<OpenIdeWizardPluginPane> {
return groupPanes.flatMap { it.selectedPlugins }
}
private fun getSelectedCount(): Int {
return groupPanes.sumOf { it.selectedCount }
}
private fun changeHandler() {
val selected = getSelected()
when(selected.size) {
val selectedSize = getSelected().size
when(selectedSize) {
0 -> {
leftLabel.text = ImportSettingsBundle.message("plugins.page.choose.counter.no")
continueAction.text = continueButtonTextOverride ?: ImportSettingsBundle.message("plugins.page.ok.button.continue.without")
@@ -52,7 +62,7 @@ internal class WizardPluginsPage(
continueAction.text = continueButtonTextOverride ?: ImportSettingsBundle.message("plugins.page.ok.button.install")
}
else -> {
leftLabel.text = ImportSettingsBundle.message("plugins.page.choose.counter.multiple", selected.size)
leftLabel.text = ImportSettingsBundle.message("plugins.page.choose.counter.multiple", selectedSize)
continueAction.text = continueButtonTextOverride ?: ImportSettingsBundle.message("plugins.page.ok.button.install")
}
}
@@ -65,14 +75,14 @@ internal class WizardPluginsPage(
border = JBUI.Borders.empty(18, 20)
})
val plugins = pluginService.plugins
val pluginGroups: List<WizardPluginGroup> = pluginService.pluginGroups
val listPane = JPanel(VerticalLayout(JBUI.scale(4))).apply {
isOpaque = false
plugins.forEach {
val pl = WizardPluginPane(it) { changeHandler() }
pluginPanes.add(pl)
add(pl.pane)
pluginGroups.forEach { group: WizardPluginGroup ->
val groupPane = OpenIdeWizardPluginGroupPane(group, controller.lifetime.coroutineScope) { changeHandler() }
groupPanes.add(groupPane)
add(groupPane.pane)
}
border = JBUI.Borders.empty(10, 0)
}
@@ -93,7 +103,7 @@ internal class WizardPluginsPage(
})
}
private val backAction = controller.createButton(ImportSettingsBundle.message("import.settings.back"), goBackAction)
private val backAction = controller.createButton(ImportSettingsBundle.message("import.settings.back"), goBackAction ?: {})
private val continueAction = controller.createDefaultButton(continueButtonTextOverride ?: ImportSettingsBundle.message("plugins.page.ok.button.continue.without")) {
val ids = getSelected().map { it.plugin.id }.toList()
@@ -101,10 +111,20 @@ internal class WizardPluginsPage(
}
init {
val buttons: List<JButton> = if (SystemInfo.isMac) {
listOf(backAction, continueAction)
val buttons: List<JButton> = buildList {
if (SystemInfo.isMac) {
if (goBackAction != null) {
add(backAction)
}
add(continueAction)
}
else {
add(continueAction)
if (goBackAction != null) {
add(backAction)
}
}
}
else listOf(continueAction, backAction)
contentPage = WizardPagePane(pane, buttons, leftLabel)