github.com/tilt-dev/tilt@v0.36.0/web/src/labels.ts (about) 1 // Helper functions for working with labels and resource groups 2 3 import Features, { Flag } from "./feature" 4 import { UIResource } from "./types" 5 6 export const UNLABELED_LABEL = "unlabeled" 7 export const TILTFILE_LABEL = "Tiltfile" 8 9 export type GroupByLabelView<T> = { 10 labels: string[] 11 labelsToResources: { [key: string]: T[] } 12 tiltfile: T[] 13 unlabeled: T[] 14 } 15 16 /** 17 * The generated type for labels is a generic object, 18 * but in reality, it's an object with string keys and values. 19 * (This is a little bit of typescript gymnastics.) 20 * 21 * `isUILabels` is a type predicate function that asserts 22 * whether or not its input is the `UILabels` type 23 * 24 * `asUILabels` safely casts its input into a `UILabels` type 25 */ 26 type UILabelsGenerated = Pick<Proto.v1ObjectMeta, "labels"> 27 28 interface UILabels extends UILabelsGenerated { 29 labels: { [key: string]: string } | undefined 30 } 31 32 function isUILabels( 33 labelsWrapper: UILabelsGenerated 34 ): labelsWrapper is UILabels { 35 return ( 36 labelsWrapper.labels === undefined || 37 typeof labelsWrapper.labels === "object" 38 ) 39 } 40 41 function asUILabels(labels: UILabelsGenerated): UILabels { 42 if (isUILabels(labels)) { 43 return labels 44 } 45 46 return { labels: undefined } as UILabels 47 } 48 49 // Following k8s practices, we treat labels with prefixes as 50 // added by external tooling and not relevant to the user 51 export function getResourceLabels(resource: UIResource): string[] { 52 // Safely cast and extract labels from a resource 53 const { labels: labelsMap } = asUILabels({ 54 labels: resource.metadata?.labels, 55 }) 56 if (!labelsMap) { 57 return [] 58 } 59 60 // Return the labels in the form of a list, not a map 61 return Object.keys(labelsMap) 62 .filter((label) => { 63 const labelHasPrefix = label.includes("/") 64 return !labelHasPrefix 65 }) 66 .map((label) => labelsMap[label]) 67 } 68 69 // Order labels alphabetically A - Z 70 export function orderLabels(labels: string[]) { 71 return [...labels].sort((a, b) => a.localeCompare(b)) 72 } 73 74 // This helper function takes a template type for the resources 75 // and a label accessor function 76 export function resourcesHaveLabels<T>( 77 features: Features, 78 resources: T[] | undefined, 79 getLabels: (resource: T) => string[] 80 ): boolean { 81 // Labels on resources are ignored if feature is not enabled 82 if (!features.isEnabled(Flag.Labels)) { 83 return false 84 } 85 86 if (resources === undefined) { 87 return false 88 } 89 90 return resources.some((r) => getLabels(r).length > 0) 91 }