#334_feature_flags_in_wi #335
| @@ -31,10 +31,10 @@ class Program: | ||||
|             .use_extension(StartupDiscordExtension) | ||||
|             .use_extension(StartupModuleExtension) | ||||
|             .use_extension(StartupMigrationExtension) | ||||
|             .use_extension(DatabaseExtension) | ||||
|             .use_extension(ConfigExtension) | ||||
|             .use_extension(InitBotExtension) | ||||
|             .use_extension(BootLogExtension) | ||||
|             .use_extension(DatabaseExtension) | ||||
|             .use_extension(AppApiExtension) | ||||
|             .use_extension(CoreExtension) | ||||
|             .use_startup(Startup) | ||||
|   | ||||
| @@ -9,6 +9,7 @@ from bot_data.migration.api_key_migration import ApiKeyMigration | ||||
| from bot_data.migration.api_migration import ApiMigration | ||||
| from bot_data.migration.auto_role_fix1_migration import AutoRoleFix1Migration | ||||
| from bot_data.migration.auto_role_migration import AutoRoleMigration | ||||
| from bot_data.migration.config_feature_flags_migration import ConfigFeatureFlagsMigration | ||||
| from bot_data.migration.config_migration import ConfigMigration | ||||
| from bot_data.migration.db_history_migration import DBHistoryMigration | ||||
| from bot_data.migration.initial_migration import InitialMigration | ||||
| @@ -46,3 +47,4 @@ class StartupMigrationExtension(StartupExtensionABC): | ||||
|         services.add_transient(MigrationABC, DBHistoryMigration)  # 06.03.2023 #246 - 1.0.0 | ||||
|         services.add_transient(MigrationABC, AchievementsMigration)  # 14.06.2023 #268 - 1.1.0 | ||||
|         services.add_transient(MigrationABC, ConfigMigration)  # 19.07.2023 #127 - 1.1.0 | ||||
|         services.add_transient(MigrationABC, ConfigFeatureFlagsMigration)  # 15.08.2023 #334 - 1.1.0 | ||||
|   | ||||
| @@ -0,0 +1,33 @@ | ||||
| from bot_core.logging.database_logger import DatabaseLogger | ||||
| from bot_data.abc.migration_abc import MigrationABC | ||||
| from bot_data.db_context import DBContext | ||||
|  | ||||
|  | ||||
| class ConfigFeatureFlagsMigration(MigrationABC): | ||||
|     name = "1.1.0_ConfigFeatureFlagsMigration" | ||||
|  | ||||
|     def __init__(self, logger: DatabaseLogger, db: DBContext): | ||||
|         MigrationABC.__init__(self) | ||||
|         self._logger = logger | ||||
|         self._db = db | ||||
|         self._cursor = db.cursor | ||||
|  | ||||
|     def upgrade(self): | ||||
|         self._logger.debug(__name__, "Running upgrade") | ||||
|  | ||||
|         self._cursor.execute( | ||||
|             str( | ||||
|                 """ALTER TABLE CFG_Technician ADD FeatureFlags JSON NULL DEFAULT JSON_OBJECT() AFTER CacheMaxMessages;""" | ||||
|             ) | ||||
|         ) | ||||
|  | ||||
|         self._cursor.execute( | ||||
|             str( | ||||
|                 """ALTER TABLE CFG_Server ADD FeatureFlags JSON NULL DEFAULT JSON_OBJECT() AFTER LoginMessageChannelId;""" | ||||
|             ) | ||||
|         ) | ||||
|  | ||||
|     def downgrade(self): | ||||
|         self._logger.debug(__name__, "Running downgrade") | ||||
|         self._cursor.execute("ALTER TABLE CFG_Technician DROP COLUMN FeatureFlags;") | ||||
|         self._cursor.execute("ALTER TABLE CFG_Server DROP COLUMN FeatureFlags;") | ||||
| @@ -143,6 +143,8 @@ class ConfigMigration(MigrationABC): | ||||
|  | ||||
|     def downgrade(self): | ||||
|         self._logger.debug(__name__, "Running downgrade") | ||||
|         self._server_downgrade() | ||||
|         self._technician_downgrade() | ||||
|  | ||||
|     def _server_downgrade(self): | ||||
|         self._cursor.execute("DROP TABLE `CFG_Server`;") | ||||
|   | ||||
| @@ -4,6 +4,7 @@ from cpl_core.configuration import ConfigurationModelABC | ||||
| from cpl_core.database import TableABC | ||||
| from cpl_query.extension import List | ||||
|  | ||||
| from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum | ||||
| from bot_data.model.server import Server | ||||
| from bot_data.model.server_team_role_ids_config import ServerTeamRoleIdsConfig | ||||
|  | ||||
| @@ -24,6 +25,7 @@ class ServerConfig(TableABC, ConfigurationModelABC): | ||||
|         help_voice_channel_id: int, | ||||
|         team_channel_id: int, | ||||
|         login_message_channel_id: int, | ||||
|         feature_flags: dict[FeatureFlagsEnum], | ||||
|         server: Server, | ||||
|         afk_channel_ids: List[int], | ||||
|         team_role_ids: List[ServerTeamRoleIdsConfig], | ||||
| @@ -45,6 +47,7 @@ class ServerConfig(TableABC, ConfigurationModelABC): | ||||
|         self._help_voice_channel_id = help_voice_channel_id | ||||
|         self._team_channel_id = team_channel_id | ||||
|         self._login_message_channel_id = login_message_channel_id | ||||
|         self._feature_flags = feature_flags | ||||
|         self._server = server | ||||
|         self._afk_channel_ids = afk_channel_ids | ||||
|         self._team_role_ids = team_role_ids | ||||
| @@ -161,6 +164,14 @@ class ServerConfig(TableABC, ConfigurationModelABC): | ||||
|     def login_message_channel_id(self, value: int): | ||||
|         self._login_message_channel_id = value | ||||
|  | ||||
|     @property | ||||
|     def feature_flags(self) -> dict[FeatureFlagsEnum]: | ||||
|         return self._feature_flags | ||||
|  | ||||
|     @feature_flags.setter | ||||
|     def feature_flags(self, value: dict[FeatureFlagsEnum]): | ||||
|         self._feature_flags = value | ||||
|  | ||||
|     @property | ||||
|     def afk_channel_ids(self) -> List[int]: | ||||
|         return self._afk_channel_ids | ||||
|   | ||||
| @@ -17,6 +17,7 @@ class ServerConfigHistory(HistoryTableABC): | ||||
|         help_voice_channel_id: int, | ||||
|         team_channel_id: int, | ||||
|         login_message_channel_id: int, | ||||
|         feature_flags: dict[str], | ||||
|         server_id: int, | ||||
|         deleted: bool, | ||||
|         date_from: str, | ||||
| @@ -39,6 +40,7 @@ class ServerConfigHistory(HistoryTableABC): | ||||
|         self._help_voice_channel_id = help_voice_channel_id | ||||
|         self._team_channel_id = team_channel_id | ||||
|         self._login_message_channel_id = login_message_channel_id | ||||
|         self._feature_flags = feature_flags | ||||
|         self._server_id = server_id | ||||
|  | ||||
|         self._deleted = deleted | ||||
| @@ -97,6 +99,10 @@ class ServerConfigHistory(HistoryTableABC): | ||||
|     def login_message_channel_id(self) -> int: | ||||
|         return self._login_message_channel_id | ||||
|  | ||||
|     @property | ||||
|     def feature_flags(self) -> dict[str]: | ||||
|         return self._feature_flags | ||||
|  | ||||
|     @property | ||||
|     def server_id(self) -> int: | ||||
|         return self._server_id | ||||
|   | ||||
| @@ -1,9 +1,12 @@ | ||||
| import json | ||||
| from datetime import datetime | ||||
|  | ||||
| from cpl_core.configuration import ConfigurationModelABC | ||||
| from cpl_core.database import TableABC | ||||
| from cpl_query.extension import List | ||||
|  | ||||
| from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum | ||||
|  | ||||
|  | ||||
| class TechnicianConfig(TableABC, ConfigurationModelABC): | ||||
|     def __init__( | ||||
| @@ -12,6 +15,7 @@ class TechnicianConfig(TableABC, ConfigurationModelABC): | ||||
|         wait_for_restart: int, | ||||
|         wait_for_shutdown: int, | ||||
|         cache_max_messages: int, | ||||
|         feature_flags: dict[FeatureFlagsEnum], | ||||
|         technician_ids: List[int], | ||||
|         ping_urls: List[str], | ||||
|         created_at: datetime = None, | ||||
| @@ -23,6 +27,7 @@ class TechnicianConfig(TableABC, ConfigurationModelABC): | ||||
|         self._wait_for_restart = wait_for_restart | ||||
|         self._wait_for_shutdown = wait_for_shutdown | ||||
|         self._cache_max_messages = cache_max_messages | ||||
|         self._feature_flags = feature_flags | ||||
|         self._technician_ids = technician_ids | ||||
|         self._ping_urls = ping_urls | ||||
|  | ||||
| @@ -66,6 +71,14 @@ class TechnicianConfig(TableABC, ConfigurationModelABC): | ||||
|     def cache_max_messages(self, value: int): | ||||
|         self._cache_max_messages = value | ||||
|  | ||||
|     @property | ||||
|     def feature_flags(self) -> dict[FeatureFlagsEnum]: | ||||
|         return self._feature_flags | ||||
|  | ||||
|     @feature_flags.setter | ||||
|     def feature_flags(self, value: dict[FeatureFlagsEnum]): | ||||
|         self._feature_flags = value | ||||
|  | ||||
|     @property | ||||
|     def technician_ids(self) -> List[int]: | ||||
|         return self._technician_ids | ||||
| @@ -104,12 +117,13 @@ class TechnicianConfig(TableABC, ConfigurationModelABC): | ||||
|         return str( | ||||
|             f""" | ||||
|                 INSERT INTO `CFG_Technician` ( | ||||
|                     `HelpCommandReferenceUrl`, `WaitForRestart`, `WaitForShutdown`, `CacheMaxMessages` | ||||
|                     `HelpCommandReferenceUrl`, `WaitForRestart`, `WaitForShutdown`, `CacheMaxMessages`, `FeatureFlags` | ||||
|                 ) VALUES ( | ||||
|                     '{self._help_command_reference_url}', | ||||
|                     {self._wait_for_restart}, | ||||
|                     {self._wait_for_shutdown}, | ||||
|                     {self._cache_max_messages} | ||||
|                     {self._cache_max_messages}, | ||||
|                     '{json.dumps(self._feature_flags)}' | ||||
|                 ); | ||||
|             """ | ||||
|         ) | ||||
| @@ -122,7 +136,8 @@ class TechnicianConfig(TableABC, ConfigurationModelABC): | ||||
|                 SET `HelpCommandReferenceUrl` = '{self._help_command_reference_url}', | ||||
|                 `WaitForRestart` = {self._wait_for_restart}, | ||||
|                 `WaitForShutdown` = {self._wait_for_shutdown}, | ||||
|                 `CacheMaxMessages` = {self._cache_max_messages} | ||||
|                 `CacheMaxMessages` = {self._cache_max_messages}, | ||||
|                 `FeatureFlags` = '{json.dumps(self._feature_flags)}' | ||||
|                 WHERE `Id` = {self._id}; | ||||
|             """ | ||||
|         ) | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| import json | ||||
|  | ||||
| from cpl_core.database.context import DatabaseContextABC | ||||
| from cpl_query.extension import List | ||||
|  | ||||
| @@ -62,11 +64,12 @@ class ServerConfigRepositoryService(ServerConfigRepositoryABC): | ||||
|             result[11], | ||||
|             result[12], | ||||
|             result[13], | ||||
|             self._servers.get_server_by_id(result[14]), | ||||
|             self._get_afk_channel_ids(result[14]), | ||||
|             self._get_team_role_ids(result[14]), | ||||
|             result[15], | ||||
|             json.loads(result[14]), | ||||
|             self._servers.get_server_by_id(result[15]), | ||||
|             self._get_afk_channel_ids(result[15]), | ||||
|             self._get_team_role_ids(result[15]), | ||||
|             result[16], | ||||
|             result[17], | ||||
|             id=result[0], | ||||
|         ) | ||||
|  | ||||
|   | ||||
| @@ -48,6 +48,7 @@ class ServerConfigSeeder(DataSeederABC): | ||||
|                     guild.system_channel.id, | ||||
|                     guild.system_channel.id, | ||||
|                     guild.system_channel.id, | ||||
|                     {}, | ||||
|                     server, | ||||
|                     [], | ||||
|                     [], | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| import json | ||||
|  | ||||
| from cpl_core.database.context import DatabaseContextABC | ||||
| from cpl_query.extension import List | ||||
|  | ||||
| @@ -41,10 +43,11 @@ class TechnicianConfigRepositoryService(TechnicianConfigRepositoryABC): | ||||
|             result[2], | ||||
|             result[3], | ||||
|             result[4], | ||||
|             json.loads(result[5]), | ||||
|             self._get_technician_ids(), | ||||
|             self._get_technician_ping_urls(), | ||||
|             result[5], | ||||
|             result[6], | ||||
|             result[7], | ||||
|             id=result[0], | ||||
|         ) | ||||
|  | ||||
|   | ||||
| @@ -32,6 +32,7 @@ class TechnicianConfigSeeder(DataSeederABC): | ||||
|                 8, | ||||
|                 8, | ||||
|                 1000000, | ||||
|                 {}, | ||||
|                 List(int, [240160344557879316]), | ||||
|                 List(str, ["www.google.com", "www.sh-edraft.de", "www.keksdose-gaming.de"]), | ||||
|             ) | ||||
|   | ||||
							
								
								
									
										9
									
								
								kdb-bot/src/bot_graphql/model/featureFlags.gql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								kdb-bot/src/bot_graphql/model/featureFlags.gql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| type FeatureFlag { | ||||
|     key: String | ||||
|     value: Boolean | ||||
| } | ||||
|  | ||||
| input FeatureFlagInput { | ||||
|     key: String | ||||
|     value: Boolean | ||||
| } | ||||
| @@ -4,6 +4,7 @@ type TechnicianConfig implements TableWithHistoryQuery { | ||||
|     waitForRestart: Int | ||||
|     waitForShutdown: Int | ||||
|     cacheMaxMessages: Int | ||||
|     featureFlags: [FeatureFlag] | ||||
|     pingURLs: [String] | ||||
|     technicianIds: [String] | ||||
|  | ||||
| @@ -21,6 +22,7 @@ type TechnicianConfigHistory implements HistoryTableQuery { | ||||
|     waitForRestart: Int | ||||
|     waitForShutdown: Int | ||||
|     cacheMaxMessages: Int | ||||
|     featureFlags: [FeatureFlag] | ||||
|  | ||||
|     deleted: Boolean | ||||
|     dateFrom: String | ||||
| @@ -55,6 +57,7 @@ input TechnicianConfigInput { | ||||
|     waitForRestart: Int | ||||
|     waitForShutdown: Int | ||||
|     cacheMaxMessages: Int | ||||
|     featureFlags: [FeatureFlagInput] | ||||
|     pingURLs: [String] | ||||
|     technicianIds: [String] | ||||
| } | ||||
| @@ -49,6 +49,11 @@ class TechnicianConfigMutation(QueryABC): | ||||
|         technician_config.cache_max_messages = ( | ||||
|             input["cacheMaxMessages"] if "cacheMaxMessages" in input else technician_config.cache_max_messages | ||||
|         ) | ||||
|         technician_config.feature_flags = ( | ||||
|             dict(zip([x["key"] for x in input["featureFlags"]], [x["value"] for x in input["featureFlags"]])) | ||||
|             if "featureFlags" in input | ||||
|             else technician_config.feature_flags | ||||
|         ) | ||||
|         technician_config.ping_urls = ( | ||||
|             List(str, input["pingURLs"]) if "pingURLs" in input else technician_config.ping_urls | ||||
|         ) | ||||
|   | ||||
| @@ -9,3 +9,7 @@ class TechnicianConfigHistoryQuery(HistoryQueryABC): | ||||
|         self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart) | ||||
|         self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown) | ||||
|         self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages) | ||||
|         self.set_field( | ||||
|             "featureFlags", | ||||
|             lambda config, *_: [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags], | ||||
|         ) | ||||
|   | ||||
| @@ -16,6 +16,10 @@ class TechnicianConfigQuery(DataQueryWithHistoryABC): | ||||
|         self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart) | ||||
|         self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown) | ||||
|         self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages) | ||||
|         self.set_field( | ||||
|             "featureFlags", | ||||
|             lambda config, *_: [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags], | ||||
|         ) | ||||
|         self.set_field("pingURLs", lambda config, *_: config.ping_urls) | ||||
|         self.set_field("technicianIds", lambda config, *_: config.technician_ids) | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								kdb-web/src/app/models/config/feature-flags.model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								kdb-web/src/app/models/config/feature-flags.model.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| export interface FeatureFlag { | ||||
|   key: string; | ||||
|   value: boolean; | ||||
| } | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { DataWithHistory } from "../data/data.model"; | ||||
| import { FeatureFlag } from "./feature-flags.model"; | ||||
|  | ||||
| export interface TechnicianConfig extends DataWithHistory { | ||||
|   id?: number; | ||||
| @@ -6,6 +7,7 @@ export interface TechnicianConfig extends DataWithHistory { | ||||
|   waitForRestart?: number; | ||||
|   waitForShutdown?: number; | ||||
|   cacheMaxMessages?: number; | ||||
|   featureFlags: FeatureFlag[]; | ||||
|   pingURLs: string[]; | ||||
|   technicianIds: string[]; | ||||
| } | ||||
|   | ||||
| @@ -167,7 +167,7 @@ export class Mutations { | ||||
|   `; | ||||
|  | ||||
|   static updateTechnicianConfig = ` | ||||
|     mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $pingURLs: [String], $technicianIds: [String]) { | ||||
|     mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $featureFlags: [FeatureFlagInput], $pingURLs: [String], $technicianIds: [String]) { | ||||
|       technicianConfig { | ||||
|         updateTechnicianConfig(input: { | ||||
|             id: $id, | ||||
| @@ -175,6 +175,7 @@ export class Mutations { | ||||
|             waitForRestart: $waitForRestart, | ||||
|             waitForShutdown: $waitForShutdown, | ||||
|             cacheMaxMessages: $cacheMaxMessages, | ||||
|             featureFlags: $featureFlags, | ||||
|             pingURLs: $pingURLs, | ||||
|             technicianIds: $technicianIds | ||||
|           }) { | ||||
| @@ -183,6 +184,10 @@ export class Mutations { | ||||
|           waitForRestart | ||||
|           waitForShutdown | ||||
|           cacheMaxMessages | ||||
|           featureFlags { | ||||
|             key | ||||
|             value | ||||
|           } | ||||
|           pingURLs | ||||
|           technicianIds | ||||
|         } | ||||
|   | ||||
| @@ -353,6 +353,10 @@ export class Queries { | ||||
|         waitForRestart | ||||
|         waitForShutdown | ||||
|         cacheMaxMessages | ||||
|         featureFlags { | ||||
|           key | ||||
|           value | ||||
|         } | ||||
|         pingURLs | ||||
|         technicianIds | ||||
|  | ||||
|   | ||||
| @@ -164,6 +164,9 @@ | ||||
|     <app-config-list translationKey="admin.settings.bot.ping_urls" [(data)]="config.pingURLs"></app-config-list> | ||||
|     <app-config-list translationKey="admin.settings.bot.technician_ids" [(data)]="config.technicianIds"></app-config-list> | ||||
|  | ||||
|     <app-feature-flag-list [(data)]="config.featureFlags"></app-feature-flag-list> | ||||
|     <div class="content-divider"></div> | ||||
|  | ||||
|     <div class="content-row"> | ||||
|       <button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn" | ||||
|               (click)="saveTechnicianConfig()"></button> | ||||
|   | ||||
| @@ -49,6 +49,7 @@ export class SettingsComponent implements OnInit { | ||||
|     waitForRestart: 0, | ||||
|     waitForShutdown: 0, | ||||
|     cacheMaxMessages: 0, | ||||
|     featureFlags: [], | ||||
|     pingURLs: [], | ||||
|     technicianIds: [] | ||||
|   }; | ||||
| @@ -150,6 +151,7 @@ export class SettingsComponent implements OnInit { | ||||
|         waitForRestart: this.config.waitForRestart, | ||||
|         waitForShutdown: this.config.waitForShutdown, | ||||
|         cacheMaxMessages: this.config.cacheMaxMessages, | ||||
|         featureFlags: this.config.featureFlags, | ||||
|         pingURLs: this.config.pingURLs, | ||||
|         technicianIds: this.config.technicianIds | ||||
|       } | ||||
|   | ||||
| @@ -15,8 +15,8 @@ | ||||
|           </div> | ||||
|         </ng-template> | ||||
|         <ng-template pTemplate="body" let-value let-editing="editing" let-ri="rowIndex"> | ||||
|           <tr [pEditableRow]="value"> | ||||
|             <td> | ||||
|           <tr [pEditableRow]="value" style="display: flex;"> | ||||
|             <td style="flex: 1;"> | ||||
|               <p-cellEditor> | ||||
|                 <ng-template pTemplate="input"> | ||||
|                   <input class="table-edit-input" pInputText type="text" [(ngModel)]="value.value"> | ||||
|   | ||||
| @@ -0,0 +1,54 @@ | ||||
| <div class="content-row"> | ||||
|   <div class="content-column"> | ||||
|     <div class="content-data-name"> | ||||
|       {{'common.feature_flags' | translate}}: | ||||
|     </div> | ||||
|     <div class="content-data-value-row"> | ||||
|       <p-table #dt [value]="internal_data" dataKey="id" editMode="row"> | ||||
|         <ng-template pTemplate="caption"> | ||||
|           <div class="table-caption"> | ||||
|             <div class="table-caption-btn-wrapper btn-wrapper"> | ||||
|               <button pButton class="icon-btn btn" | ||||
|                       icon="pi pi-plus" (click)="addNew(dt)"> | ||||
|               </button> | ||||
|             </div> | ||||
|           </div> | ||||
|         </ng-template> | ||||
|         <ng-template pTemplate="body" let-value let-editing="editing" let-ri="rowIndex"> | ||||
|           <tr [pEditableRow]="value" style="display: flex;"> | ||||
|             <td style="flex: 3;"> | ||||
|               <p-cellEditor> | ||||
|                 <ng-template pTemplate="input"> | ||||
|                   <input class="table-edit-input" pInputText type="text" [(ngModel)]="value.value.key"> | ||||
|                 </ng-template> | ||||
|                 <ng-template pTemplate="output"> | ||||
|                   {{value.value.key}} | ||||
|                 </ng-template> | ||||
|               </p-cellEditor> | ||||
|             </td> | ||||
|             <td style="flex: 1;"> | ||||
|               <p-cellEditor> | ||||
|                 <ng-template pTemplate="input"> | ||||
|                   <p-inputSwitch class="table-edit-input" [(ngModel)]="value.value.value"></p-inputSwitch> | ||||
|                 </ng-template> | ||||
|                 <ng-template pTemplate="output"> | ||||
|                   <p-inputSwitch class="table-edit-input" [(ngModel)]="value.value.value" [disabled]="true"></p-inputSwitch> | ||||
|                 </ng-template> | ||||
|               </p-cellEditor> | ||||
|             </td> | ||||
|             <td> | ||||
|               <div class="btn-wrapper"> | ||||
|                 <button *ngIf="!editing" pButton type="button" pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" (click)="editInit(value, ri)"></button> | ||||
|                 <button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash" (click)="delete(ri)"></button> | ||||
|  | ||||
|                 <button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check" (click)="editSave(value, ri)"></button> | ||||
|                 <button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn" icon="pi pi-times" | ||||
|                         (click)="editCancel(ri)"></button> | ||||
|               </div> | ||||
|             </td> | ||||
|           </tr> | ||||
|         </ng-template> | ||||
|       </p-table> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
| @@ -0,0 +1,23 @@ | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||||
|  | ||||
| import { FeatureFlagListComponent } from './feature-flag-list.component'; | ||||
|  | ||||
| describe('FeatureFlagListComponent', () => { | ||||
|   let component: FeatureFlagListComponent; | ||||
|   let fixture: ComponentFixture<FeatureFlagListComponent>; | ||||
|  | ||||
|   beforeEach(async () => { | ||||
|     await TestBed.configureTestingModule({ | ||||
|       declarations: [ FeatureFlagListComponent ] | ||||
|     }) | ||||
|     .compileComponents(); | ||||
|  | ||||
|     fixture = TestBed.createComponent(FeatureFlagListComponent); | ||||
|     component = fixture.componentInstance; | ||||
|     fixture.detectChanges(); | ||||
|   }); | ||||
|  | ||||
|   it('should create', () => { | ||||
|     expect(component).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
| @@ -0,0 +1,28 @@ | ||||
| import { Component } from "@angular/core"; | ||||
| import { ConfigListComponent } from "../config-list/config-list.component"; | ||||
| import { Table } from "primeng/table"; | ||||
|  | ||||
| @Component({ | ||||
|   selector: "app-feature-flag-list", | ||||
|   templateUrl: "./feature-flag-list.component.html", | ||||
|   styleUrls: ["./feature-flag-list.component.scss"] | ||||
| }) | ||||
| export class FeatureFlagListComponent extends ConfigListComponent { | ||||
|   options: boolean[] = [true, false]; | ||||
|  | ||||
|   constructor() { | ||||
|     super(); | ||||
|   } | ||||
|  | ||||
|   override addNew(table: Table) { | ||||
|     const id = Math.max.apply(Math, this.internal_data.map(value => { | ||||
|       return value.id ?? 0; | ||||
|     })) + 1; | ||||
|     const newItem = { id: id, value: {key: "", value: false} }; | ||||
|     this.internal_data.push(newItem); | ||||
|  | ||||
|     table.initRowEdit(newItem); | ||||
|     const index = this.internal_data.findIndex(l => l.id == newItem.id); | ||||
|     this.editInit(newItem, index); | ||||
|   } | ||||
| } | ||||
| @@ -30,6 +30,8 @@ import { MultiSelectModule } from "primeng/multiselect"; | ||||
| import { HideableColumnComponent } from './components/hideable-column/hideable-column.component'; | ||||
| import { HideableHeaderComponent } from './components/hideable-header/hideable-header.component'; | ||||
| import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-select-columns.component'; | ||||
| import { FeatureFlagListComponent } from './components/feature-flag-list/feature-flag-list.component'; | ||||
| import { InputSwitchModule } from "primeng/inputswitch"; | ||||
|  | ||||
|  | ||||
| @NgModule({ | ||||
| @@ -42,6 +44,7 @@ import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-s | ||||
|     HideableColumnComponent, | ||||
|     HideableHeaderComponent, | ||||
|     MultiSelectColumnsComponent, | ||||
|     FeatureFlagListComponent, | ||||
|   ], | ||||
|   imports: [ | ||||
|     CommonModule, | ||||
| @@ -68,6 +71,7 @@ import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-s | ||||
|     SidebarModule, | ||||
|     DataViewModule, | ||||
|     MultiSelectModule, | ||||
|     InputSwitchModule, | ||||
|   ], | ||||
|   exports: [ | ||||
|     ButtonModule, | ||||
| @@ -102,6 +106,8 @@ import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-s | ||||
|     HideableColumnComponent, | ||||
|     HideableHeaderComponent, | ||||
|     MultiSelectColumnsComponent, | ||||
|     FeatureFlagListComponent, | ||||
|     InputSwitchModule, | ||||
|   ] | ||||
| }) | ||||
| export class SharedModule { | ||||
|   | ||||
| @@ -122,6 +122,7 @@ | ||||
|     } | ||||
|   }, | ||||
|   "common": { | ||||
|     "feature_flags": "Funktionen", | ||||
|     "404": "404 - Der Eintrag konnte nicht gefunden werden", | ||||
|     "actions": "Aktionen", | ||||
|     "active": "Aktiv", | ||||
|   | ||||
| @@ -587,7 +587,7 @@ | ||||
|  | ||||
|   .p-datatable .p-sortable-column.p-highlight, | ||||
|   .p-datatable .p-sortable-column.p-highlight .p-sortable-column-icon, | ||||
|   .p-datatable .p-sortable-column:not(.p-highlight):hover{ | ||||
|   .p-datatable .p-sortable-column:not(.p-highlight):hover { | ||||
|     color: $primaryHeaderColor !important; | ||||
|     background-color: transparent !important; | ||||
|   } | ||||
| @@ -672,4 +672,13 @@ | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .p-inputswitch.p-inputswitch-checked .p-inputswitch-slider { | ||||
|     background: $primaryHeaderColor !important; | ||||
|   } | ||||
|  | ||||
|   .p-inputswitch.p-focus .p-inputswitch-slider { | ||||
|     box-shadow: none !important; | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user