Files
ComfyUI_frontend/src/composables/useFeatureFlags.ts
AustinMroz 25afd39d2b linear v2: Simple Mode (#7734)
A major, full rewrite of linear mode, now under the name "Simple Mode". 
- Fixes widget styling
- Adds a new simplified history
- Adds support for non-image outputs
- Supports right sidebar
- Allows and panning on the output image preview
- Provides support for drag and drop zones
- Moves workflow notes into a popover.
- Allows scrolling through outputs with Ctrl+scroll or arrow keys

The primary means of accessing Simple Mode is a toggle button on the
bottom right. This button is only shown if a feature flag is enabled, or
the user has already seen linear mode during the current session. Simple
Mode can also be accessed by
- Using the toggle linear mode keybind
- Loading a workflow that that was saved in Simple Mode workflow
- Loading a template url with appropriate parameter

<img width="1790" height="1387" alt="image"
src="https://github.com/user-attachments/assets/d86a4a41-dfbf-41e7-a6d9-146473005606"
/>

Known issues:
- Outputs on cloud are not filtered to those produced by the current
workflow.
  - Output filtering has been globally disabled for consistency
- Outputs will load more items on scroll, but does not unload
- Performance may be reduced on weak devices with very large histories.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7734-linear-v2-2d16d73d3650819b8a10f150ff12ea22)
by [Unito](https://www.unito.io)
2026-01-13 20:18:31 -08:00

106 lines
3.4 KiB
TypeScript

import { computed, reactive, readonly } from 'vue'
import { remoteConfig } from '@/platform/remoteConfig/remoteConfig'
import { api } from '@/scripts/api'
/**
* Known server feature flags (top-level, not extensions)
*/
export enum ServerFeatureFlag {
SUPPORTS_PREVIEW_METADATA = 'supports_preview_metadata',
MAX_UPLOAD_SIZE = 'max_upload_size',
MANAGER_SUPPORTS_V4 = 'extension.manager.supports_v4',
MODEL_UPLOAD_BUTTON_ENABLED = 'model_upload_button_enabled',
ASSET_DELETION_ENABLED = 'asset_deletion_enabled',
ASSET_RENAME_ENABLED = 'asset_rename_enabled',
PRIVATE_MODELS_ENABLED = 'private_models_enabled',
ONBOARDING_SURVEY_ENABLED = 'onboarding_survey_enabled',
HUGGINGFACE_MODEL_IMPORT_ENABLED = 'huggingface_model_import_enabled',
LINEAR_TOGGLE_ENABLED = 'linear_toggle_enabled',
ASYNC_MODEL_UPLOAD_ENABLED = 'async_model_upload_enabled'
}
/**
* Composable for reactive access to server-side feature flags
*/
export function useFeatureFlags() {
const flags = reactive({
get supportsPreviewMetadata() {
return api.getServerFeature(ServerFeatureFlag.SUPPORTS_PREVIEW_METADATA)
},
get maxUploadSize() {
return api.getServerFeature(ServerFeatureFlag.MAX_UPLOAD_SIZE)
},
get supportsManagerV4() {
return api.getServerFeature(ServerFeatureFlag.MANAGER_SUPPORTS_V4)
},
get modelUploadButtonEnabled() {
// Check remote config first (from /api/features), fall back to websocket feature flags
return (
remoteConfig.value.model_upload_button_enabled ??
api.getServerFeature(
ServerFeatureFlag.MODEL_UPLOAD_BUTTON_ENABLED,
false
)
)
},
get assetDeletionEnabled() {
return (
remoteConfig.value.asset_deletion_enabled ??
api.getServerFeature(ServerFeatureFlag.ASSET_DELETION_ENABLED, false)
)
},
get assetRenameEnabled() {
return (
remoteConfig.value.asset_rename_enabled ??
api.getServerFeature(ServerFeatureFlag.ASSET_RENAME_ENABLED, false)
)
},
get privateModelsEnabled() {
// Check remote config first (from /api/features), fall back to websocket feature flags
return (
remoteConfig.value.private_models_enabled ??
api.getServerFeature(ServerFeatureFlag.PRIVATE_MODELS_ENABLED, false)
)
},
get onboardingSurveyEnabled() {
return (
remoteConfig.value.onboarding_survey_enabled ??
api.getServerFeature(ServerFeatureFlag.ONBOARDING_SURVEY_ENABLED, true)
)
},
get huggingfaceModelImportEnabled() {
return (
remoteConfig.value.huggingface_model_import_enabled ??
api.getServerFeature(
ServerFeatureFlag.HUGGINGFACE_MODEL_IMPORT_ENABLED,
false
)
)
},
get linearToggleEnabled() {
return (
remoteConfig.value.linear_toggle_enabled ??
api.getServerFeature(ServerFeatureFlag.LINEAR_TOGGLE_ENABLED, false)
)
},
get asyncModelUploadEnabled() {
return (
remoteConfig.value.async_model_upload_enabled ??
api.getServerFeature(
ServerFeatureFlag.ASYNC_MODEL_UPLOAD_ENABLED,
false
)
)
}
})
const featureFlag = <T = unknown>(featurePath: string, defaultValue?: T) =>
computed(() => api.getServerFeature(featurePath, defaultValue))
return {
flags: readonly(flags),
featureFlag
}
}