diff --git a/app/index.js b/app/index.js index 6b6a5c851..91644f718 100644 --- a/app/index.js +++ b/app/index.js @@ -5,9 +5,6 @@ import './i18n'; import angular from 'angular'; import { UI_ROUTER_REACT_HYBRID } from '@uirouter/react-hybrid'; -import { Edition } from '@/react/portainer/feature-flags/enums'; -import { init as initFeatureService } from '@/react/portainer/feature-flags/feature-flags.service'; - import './agent'; import { azureModule } from './azure'; import './docker/__module'; @@ -30,8 +27,6 @@ if (window.origin == 'http://localhost:49000') { document.getElementById('base').href = basePath; } -initFeatureService(Edition[process.env.PORTAINER_EDITION]); - angular .module('portainer', [ 'ui.bootstrap', diff --git a/app/react/portainer/feature-flags/enums.ts b/app/react/portainer/feature-flags/enums.ts deleted file mode 100644 index ea3c2b0b2..000000000 --- a/app/react/portainer/feature-flags/enums.ts +++ /dev/null @@ -1,46 +0,0 @@ -export enum Edition { - CE, - BE, -} - -export enum FeatureState { - HIDDEN, - VISIBLE, - LIMITED_BE, -} - -export enum FeatureId { - K8S_RESOURCE_POOL_LB_QUOTA = 'k8s-resourcepool-Ibquota', - K8S_RESOURCE_POOL_STORAGE_QUOTA = 'k8s-resourcepool-storagequota', - K8S_CREATE_FROM_KUBECONFIG = 'k8s-create-from-kubeconfig', - K8S_EDIT_YAML = 'k8s-edit-yaml', - KAAS_PROVISIONING = 'kaas-provisioning', - RBAC_ROLES = 'rbac-roles', - REGISTRY_MANAGEMENT = 'registry-management', - K8S_SETUP_DEFAULT = 'k8s-setup-default', - S3_BACKUP_SETTING = 's3-backup-setting', - S3_RESTORE = 'restore-s3-form', - HIDE_INTERNAL_AUTHENTICATION_PROMPT = 'hide-internal-authentication-prompt', - TEAM_MEMBERSHIP = 'team-membership', - HIDE_INTERNAL_AUTH = 'hide-internal-auth', - EXTERNAL_AUTH_LDAP = 'external-auth-ldap', - ACTIVITY_AUDIT = 'activity-audit', - FORCE_REDEPLOYMENT = 'force-redeployment', - HIDE_AUTO_UPDATE_WINDOW = 'hide-auto-update-window', - IMAGE_UP_TO_DATE_INDICATOR = 'image-up-to-date-indicator', - STACK_PULL_IMAGE = 'stack-pull-image', - STACK_WEBHOOK = 'stack-webhook', - CONTAINER_WEBHOOK = 'container-webhook', - POD_SECURITY_POLICY_CONSTRAINT = 'pod-security-policy-constraint', - HIDE_DOCKER_HUB_ANONYMOUS = 'hide-docker-hub-anonymous', - CUSTOM_LOGIN_BANNER = 'custom-login-banner', - ENFORCE_DEPLOYMENT_OPTIONS = 'k8s-enforce-deployment-options', - K8S_ADM_ONLY_USR_INGRESS_DEPLY = 'k8s-admin-only-ingress-deploy', - K8S_ADM_ONLY_SECRETS = 'k8s-admin-only-secrets', - K8S_ROLLING_RESTART = 'k8s-rolling-restart', - K8SINSTALL = 'k8s-install', - KUBESOLO = 'kubesolo', - K8S_ANNOTATIONS = 'k8s-annotations', - CA_FILE = 'ca-file', - K8S_REQUIRE_NOTE_ON_APPLICATIONS = 'k8s-note-on-applications', -} diff --git a/app/react/portainer/feature-flags/feature-flags.css b/app/react/portainer/feature-flags/feature-flags.css deleted file mode 100644 index fc6526951..000000000 --- a/app/react/portainer/feature-flags/feature-flags.css +++ /dev/null @@ -1,62 +0,0 @@ -.form-control.limited-be { - border-color: var(--BE-only); -} - -.form-control.limited-be.no-border { - border-color: var(--border-form-control-color); -} - -button.limited-be, -button[disabled].limited-be.oauth-save-settings-button { - background-color: var(--BE-only); - border-color: var(--BE-only); - margin-left: 0px; -} - -button.limited-be.oauth-save-settings-button { - background-color: var(--blue-2); - border-color: transparent; - margin-left: 0px; -} - -ng-form.limited-be, -form.limited-be, -div.limited-be { - border: solid 1px var(--BE-only); - border-radius: 8px; - pointer-events: none; - touch-action: none; - display: block; -} - -.limited-be-content { - @apply border-gray-6 p-2.5 opacity-50; -} - -.limited-be-link { - padding: 10px; - width: inherit; - z-index: 5; - position: absolute; - top: 0px; - right: 0px; - float: right; - border-top-right-radius: 8px; - border-bottom-left-radius: 8px; - touch-action: auto; - cursor: hand; - pointer-events: auto; -} - -.limited-be-link a { - @apply text-gray-6; -} - -.limited-be-link a:hover { - @apply underline; - @apply border-blue-9 text-blue-9; -} - -.form-control.limited-be[disabled] { - background-color: transparent !important; -} diff --git a/app/react/portainer/feature-flags/feature-flags.service.ts b/app/react/portainer/feature-flags/feature-flags.service.ts deleted file mode 100644 index 42244618f..000000000 --- a/app/react/portainer/feature-flags/feature-flags.service.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Edition, FeatureId, FeatureState } from './enums'; - -export const isBE = process.env.PORTAINER_EDITION === 'BE'; -interface ServiceState { - currentEdition: Edition; - features: Record; -} - -const state: ServiceState = { - currentEdition: Edition.CE, - features: >{}, -}; - -export async function init(edition: Edition) { - // will be loaded on runtime - const currentEdition = edition; - const features = { - [FeatureId.K8S_RESOURCE_POOL_LB_QUOTA]: Edition.BE, - [FeatureId.K8S_RESOURCE_POOL_STORAGE_QUOTA]: Edition.BE, - [FeatureId.K8S_CREATE_FROM_KUBECONFIG]: Edition.BE, - [FeatureId.KAAS_PROVISIONING]: Edition.BE, - [FeatureId.K8SINSTALL]: Edition.BE, - [FeatureId.KUBESOLO]: Edition.BE, - [FeatureId.ACTIVITY_AUDIT]: Edition.BE, - [FeatureId.EXTERNAL_AUTH_LDAP]: Edition.BE, - [FeatureId.HIDE_INTERNAL_AUTH]: Edition.BE, - [FeatureId.HIDE_INTERNAL_AUTHENTICATION_PROMPT]: Edition.BE, - [FeatureId.K8S_SETUP_DEFAULT]: Edition.BE, - [FeatureId.RBAC_ROLES]: Edition.BE, - [FeatureId.REGISTRY_MANAGEMENT]: Edition.BE, - [FeatureId.S3_BACKUP_SETTING]: Edition.BE, - [FeatureId.S3_RESTORE]: Edition.BE, - [FeatureId.TEAM_MEMBERSHIP]: Edition.BE, - [FeatureId.FORCE_REDEPLOYMENT]: Edition.BE, - [FeatureId.HIDE_AUTO_UPDATE_WINDOW]: Edition.BE, - [FeatureId.IMAGE_UP_TO_DATE_INDICATOR]: Edition.BE, - [FeatureId.STACK_PULL_IMAGE]: Edition.BE, - [FeatureId.STACK_WEBHOOK]: Edition.BE, - [FeatureId.CONTAINER_WEBHOOK]: Edition.BE, - [FeatureId.POD_SECURITY_POLICY_CONSTRAINT]: Edition.BE, - [FeatureId.HIDE_DOCKER_HUB_ANONYMOUS]: Edition.BE, - [FeatureId.CUSTOM_LOGIN_BANNER]: Edition.BE, - [FeatureId.K8S_EDIT_YAML]: Edition.BE, - [FeatureId.ENFORCE_DEPLOYMENT_OPTIONS]: Edition.BE, - [FeatureId.K8S_ADM_ONLY_USR_INGRESS_DEPLY]: Edition.BE, - [FeatureId.K8S_ADM_ONLY_SECRETS]: Edition.BE, - [FeatureId.K8S_ROLLING_RESTART]: Edition.BE, - [FeatureId.K8S_ANNOTATIONS]: Edition.BE, - [FeatureId.CA_FILE]: Edition.BE, - [FeatureId.K8S_REQUIRE_NOTE_ON_APPLICATIONS]: Edition.BE, - }; - - state.currentEdition = currentEdition; - state.features = features; -} - -export function selectShow(featureId?: FeatureId) { - if (!featureId) { - return FeatureState.VISIBLE; - } - - if (!state.features[featureId]) { - return FeatureState.HIDDEN; - } - - if (state.features[featureId] <= state.currentEdition) { - return FeatureState.VISIBLE; - } - - if (state.features[featureId] === Edition.BE) { - return FeatureState.LIMITED_BE; - } - - return FeatureState.HIDDEN; -} - -export function isLimitedToBE(featureId?: FeatureId) { - return selectShow(featureId) === FeatureState.LIMITED_BE; -} diff --git a/app/react/portainer/feature-flags/index.ts b/app/react/portainer/feature-flags/index.ts deleted file mode 100644 index 68d713db5..000000000 --- a/app/react/portainer/feature-flags/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import angular from 'angular'; - -import { limitedFeatureDirective } from './limited-feature.directive'; -import './feature-flags.css'; - -export default angular - .module('portainer.feature-flags', []) - .directive('limitedFeatureDir', limitedFeatureDirective).name; diff --git a/app/react/portainer/feature-flags/limited-feature.directive.ts b/app/react/portainer/feature-flags/limited-feature.directive.ts deleted file mode 100644 index bed534ab1..000000000 --- a/app/react/portainer/feature-flags/limited-feature.directive.ts +++ /dev/null @@ -1,44 +0,0 @@ -import _ from 'lodash'; -import { IAttributes, IDirective, IScope } from 'angular'; - -import { FeatureState } from '@/react/portainer/feature-flags/enums'; - -import { selectShow } from './feature-flags.service'; - -const BASENAME = 'limitedFeature'; - -/* @ngInject */ -export function limitedFeatureDirective(): IDirective { - return { - restrict: 'A', - link, - }; - - function link(scope: IScope, elem: JQLite, attrs: IAttributes) { - const { limitedFeatureDir: featureId } = attrs; - - if (!featureId) { - return; - } - - const limitedFeatureAttrs = Object.keys(attrs) - .filter((attr) => attr.startsWith(BASENAME) && attr !== `${BASENAME}Dir`) - .map((attr) => [_.kebabCase(attr.replace(BASENAME, '')), attrs[attr]]); - - const state = selectShow(featureId); - - if (state === FeatureState.HIDDEN) { - elem.hide(); - return; - } - - if (state === FeatureState.VISIBLE) { - return; - } - - limitedFeatureAttrs.forEach(([attr, value = attr]) => { - const currentValue = elem.attr(attr) || ''; - elem.attr(attr, `${currentValue} ${value}`.trim()); - }); - } -} diff --git a/app/react/portainer/feature-flags/withEdition.tsx b/app/react/portainer/feature-flags/withEdition.tsx deleted file mode 100644 index 3572ca35e..000000000 --- a/app/react/portainer/feature-flags/withEdition.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { ComponentType } from 'react'; - -export function withEdition( - WrappedComponent: ComponentType, - edition: 'BE' | 'CE' -): ComponentType { - // Try to create a nice displayName for React Dev Tools. - const displayName = - WrappedComponent.displayName || WrappedComponent.name || 'Component'; - - function WrapperComponent(props: T & JSX.IntrinsicAttributes) { - if (process.env.PORTAINER_EDITION !== edition) { - return null; - } - - return ; - } - - WrapperComponent.displayName = `with${edition}Edition(${displayName})`; - - return WrapperComponent; -}