Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | 1x 1x 1x 1x 197x 197x 197x 167x 167x 1x 166x 166x 6x 160x 93x 67x 67x 67x 67x 30x 4x 116x 4x 173x 171x 171x 167x 167x 167x | import { WorkItemWidgetType, WorkItemWidgetTypes } from "../graphql/workItems"; import { ConnectionManager } from "./ConnectionManager"; import { GitLabTier } from "./GitLabVersionDetector"; interface WidgetRequirement { tier: GitLabTier | "free"; minVersion: number; } export class WidgetAvailability { private static widgetRequirements: Record<WorkItemWidgetType, WidgetRequirement> = { // Free tier widgets (available to all) [WorkItemWidgetTypes.ASSIGNEES]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.DESCRIPTION]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.HIERARCHY]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.LABELS]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.MILESTONE]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.NOTES]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.START_AND_DUE_DATE]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.STATUS]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.NOTIFICATIONS]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.CURRENT_USER_TODOS]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.AWARD_EMOJI]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.PARTICIPANTS]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.DESIGNS]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.DEVELOPMENT]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.TIME_TRACKING]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.ERROR_TRACKING]: { tier: "free", minVersion: 15.0 }, // Premium tier widgets [WorkItemWidgetTypes.WEIGHT]: { tier: "premium", minVersion: 15.0 }, [WorkItemWidgetTypes.ITERATION]: { tier: "premium", minVersion: 15.0 }, [WorkItemWidgetTypes.LINKED_ITEMS]: { tier: "premium", minVersion: 15.0 }, [WorkItemWidgetTypes.CRM_CONTACTS]: { tier: "premium", minVersion: 16.0 }, [WorkItemWidgetTypes.EMAIL_PARTICIPANTS]: { tier: "premium", minVersion: 16.0 }, [WorkItemWidgetTypes.LINKED_RESOURCES]: { tier: "premium", minVersion: 16.5 }, // Ultimate tier widgets [WorkItemWidgetTypes.HEALTH_STATUS]: { tier: "ultimate", minVersion: 15.0 }, [WorkItemWidgetTypes.CUSTOM_FIELDS]: { tier: "ultimate", minVersion: 17.0 }, [WorkItemWidgetTypes.VULNERABILITIES]: { tier: "ultimate", minVersion: 15.0 }, // Legacy widgets (may not be available) [WorkItemWidgetTypes.PROGRESS]: { tier: "free", minVersion: 15.0 }, [WorkItemWidgetTypes.REQUIREMENT_LEGACY]: { tier: "ultimate", minVersion: 13.1 }, [WorkItemWidgetTypes.TEST_REPORTS]: { tier: "ultimate", minVersion: 13.6 }, [WorkItemWidgetTypes.COLOR]: { tier: "free", minVersion: 15.0 }, }; public static isWidgetAvailable(widget: WorkItemWidgetType): boolean { const connectionManager = ConnectionManager.getInstance(); try { const instanceInfo = connectionManager.getInstanceInfo(); const requirement = this.widgetRequirements[widget]; if (!requirement) { // Unknown widget, assume not available return false; } // Check version requirement const version = this.parseVersion(instanceInfo.version); if (version < requirement.minVersion) { return false; } // Check tier requirement if (requirement.tier === "free") { return true; // Available to all tiers } const tierHierarchy: Record<GitLabTier, number> = { free: 0, premium: 1, ultimate: 2, }; const requiredTierLevel = tierHierarchy[requirement.tier as GitLabTier]; const actualTierLevel = tierHierarchy[instanceInfo.tier]; return actualTierLevel >= requiredTierLevel; } catch { // If connection not initialized, assume widget not available return false; } } public static getAvailableWidgets(): WorkItemWidgetType[] { return Object.values(WorkItemWidgetTypes).filter( (widget): widget is WorkItemWidgetType => typeof widget === "string" && this.isWidgetAvailable(widget as WorkItemWidgetType) ); } public static getWidgetRequirement(widget: WorkItemWidgetType): WidgetRequirement | undefined { return this.widgetRequirements[widget]; } private static parseVersion(version: string): number { if (version === "unknown") return 0; const match = version.match(/^(\d+)\.(\d+)/); if (!match) return 0; const major = parseInt(match[1], 10); const minor = parseInt(match[2], 10); return major + minor / 10; } } |