From 30ce8872737076eb9f1d6848fe8a96671f5da45e Mon Sep 17 00:00:00 2001 From: Pavel Ashevskiy Date: Tue, 30 Mar 2021 18:17:18 +0400 Subject: [PATCH] Remove badges, simplify implementation Signed-off-by: Pavel Ashevskiy --- package.json | 1 + .../components/dock/create-resource.scss | 23 -- .../components/dock/create-resource.store.ts | 92 +++----- .../components/dock/create-resource.tsx | 45 +--- templates/create-resource/ClusterRole.yaml | 198 ++++++++++++++++++ .../create-resource/ClusterRoleBinding.yaml | 12 ++ .../{configuration => }/ConfigMap.yaml | 0 .../{k8s-workloads => }/CronJob.yaml | 0 .../{k8s-workloads => }/DeamonSet.yaml | 0 .../{k8s-workloads => }/Deployment.yaml | 0 .../{networking => }/Ingress.yaml | 0 .../{k8s-workloads => }/Job.yaml | 0 .../{networking => }/NetworkPolicy.yaml | 0 .../{storage => }/PersistentVolume.yaml | 0 .../{storage => }/PersistentVolumeClaim.yaml | 0 .../{k8s-workloads => }/ReplicaSet.yaml | 0 .../ReplicationController.yaml | 0 .../{access-control => }/Role.yaml | 0 .../{access-control => }/RoleBinding.yaml | 0 .../{configuration => }/Secret.yaml | 0 .../{networking => }/Service.yaml | 0 .../{k8s-workloads => }/StatefulSet.yaml | 0 .../access-control/ClusterRole.yaml | 12 -- .../access-control/ClusterRoleBinding.yaml | 13 -- yarn.lock | 47 ++++- 25 files changed, 292 insertions(+), 151 deletions(-) create mode 100644 templates/create-resource/ClusterRole.yaml create mode 100644 templates/create-resource/ClusterRoleBinding.yaml rename templates/create-resource/{configuration => }/ConfigMap.yaml (100%) rename templates/create-resource/{k8s-workloads => }/CronJob.yaml (100%) rename templates/create-resource/{k8s-workloads => }/DeamonSet.yaml (100%) rename templates/create-resource/{k8s-workloads => }/Deployment.yaml (100%) rename templates/create-resource/{networking => }/Ingress.yaml (100%) rename templates/create-resource/{k8s-workloads => }/Job.yaml (100%) rename templates/create-resource/{networking => }/NetworkPolicy.yaml (100%) rename templates/create-resource/{storage => }/PersistentVolume.yaml (100%) rename templates/create-resource/{storage => }/PersistentVolumeClaim.yaml (100%) rename templates/create-resource/{k8s-workloads => }/ReplicaSet.yaml (100%) rename templates/create-resource/{k8s-workloads => }/ReplicationController.yaml (100%) rename templates/create-resource/{access-control => }/Role.yaml (100%) rename templates/create-resource/{access-control => }/RoleBinding.yaml (100%) rename templates/create-resource/{configuration => }/Secret.yaml (100%) rename templates/create-resource/{networking => }/Service.yaml (100%) rename templates/create-resource/{k8s-workloads => }/StatefulSet.yaml (100%) delete mode 100644 templates/create-resource/access-control/ClusterRole.yaml delete mode 100644 templates/create-resource/access-control/ClusterRoleBinding.yaml diff --git a/package.json b/package.json index bb82612ea2..e80f47352d 100644 --- a/package.json +++ b/package.json @@ -206,6 +206,7 @@ "electron-devtools-installer": "^3.1.1", "electron-updater": "^4.3.1", "electron-window-state": "^5.0.3", + "filehound": "^1.17.4", "filenamify": "^4.1.0", "fs-extra": "^9.0.1", "handlebars": "^4.7.6", diff --git a/src/renderer/components/dock/create-resource.scss b/src/renderer/components/dock/create-resource.scss index 469045fc8c..48231378c9 100644 --- a/src/renderer/components/dock/create-resource.scss +++ b/src/renderer/components/dock/create-resource.scss @@ -1,25 +1,2 @@ .CreateResource { - .Select { - .Select__single-value { - width: 100% - } - &.TemplateSelect { - min-width: 200px; - } - } -} -.select-template-item{ - justify-content: space-between; - align-items: baseline; - - .select-template-badge { - text-transform: none; - font-weight: normal; - } -} - -.select-template-group { - span { - font-size: 13px - } } diff --git a/src/renderer/components/dock/create-resource.store.ts b/src/renderer/components/dock/create-resource.store.ts index 93154c901b..13fb242678 100644 --- a/src/renderer/components/dock/create-resource.store.ts +++ b/src/renderer/components/dock/create-resource.store.ts @@ -1,21 +1,11 @@ -import fs from "fs-extra"; import path from "path"; -import os from "os" -import chokidar from "chokidar" -import filehound from "filehound" +import os from "os"; +import groupBy from "lodash/groupBy"; +import filehound from "filehound"; +import { watch } from "chokidar"; import { autobind } from "../../utils"; import { DockTabStore } from "./dock-tab.store"; import { dockStore, IDockTab, TabKind } from "./dock.store"; -import { GroupSelectOption, SelectOption} from "../select"; - -export interface BadgedSelectOption extends SelectOption { - badge?: string; -} - -export interface BadgedGroupSelectOption extends GroupSelectOption { - badge?: string; -} - @autobind() export class CreateResourceStore extends DockTabStore { @@ -34,66 +24,34 @@ export class CreateResourceStore extends DockTabStore { return path.join(os.homedir(), ".k8slens", "templates"); } - - async getTemplates(templatesPath: string):Promise{ - const ungroupedTemplates:SelectOption[] = []; - const templates:GroupSelectOption[] = []; - let groups = await fs.readdir(templatesPath); - await Promise.all(groups.map(async (group) =>{ - const groupAbsPath = path.join(templatesPath, group); - if((await fs.stat(groupAbsPath)).isDirectory()){ - const files = await fs.readdir(groupAbsPath); - const templateSelectOptions = await Promise.all(files.map( - (template) => ({ - value: path.join(groupAbsPath,template), - label: path.parse(template).name - }) - ) - ); - templates.push({label: group.replace("-", " "), options: templateSelectOptions}); - } else { - ungroupedTemplates.push({ value: groupAbsPath, label: path.parse(group).name}); - } - })) - if (ungroupedTemplates.length > 0){ - templates.push({label: "ungrouped", options: ungroupedTemplates}) - } - return templates; + get lensTemplates() { + return this.getTemplates(this.lensTemplatesFolder, "lens"); } - async getMergedTemplates():Promise { - const lensTemplates = await this.getTemplates(this.lensTemplatesFolder); - const userTemplates = await this.getTemplates(this.userTemplatesFolder); - const userGroupOptions:BadgedGroupSelectOption[] = userTemplates.filter( - ({label}) => !lensTemplates.map(({label}) => label.toString().toLowerCase()).includes(label.toString().toLowerCase()) - ).map(({label,options}) => ({label, badge:"user", options})); - // merge lens and user templates within lens groups, then merge lens and user groups - const badgedTemplates:BadgedGroupSelectOption[] = lensTemplates.map( ({label, options}) => { - const userOptions = userTemplates.find(userTemplate => userTemplate.label.toString().toLowerCase() == label.toString().toLowerCase()) - return { - label, - options: userOptions ? options.concat(userOptions.options.map((userOption) => ({label: userOption.label, badge: "user", value: userOption.value}))) : options - }; - }) - return this.orderTemplatesGroups(userGroupOptions).concat(this.orderTemplatesGroups(badgedTemplates)); + getTemplates(templatesPath: string, defaultGroup: string) { + const templates = filehound.create().path(templatesPath).ext("yaml").depth(1).findSync(); + + return templates ? (groupBy(templates,(v:string) => path.relative(templatesPath,v).split(path.sep).length>1 + ? path.parse(path.relative(templatesPath,v)).dir + : defaultGroup)) : {}; + } + + async getMergedTemplates() { + return {...this.getTemplates(this.userTemplatesFolder, "ungrouped"),...this.lensTemplates}; } async watchUserTemplates(calback: ()=> void){ - - chokidar.watch(this.userTemplatesFolder).on('all', () => { - calback(); + calback(); + watch(this.userTemplatesFolder, { + depth: 1, + ignoreInitial: true, + awaitWriteFinish: { + stabilityThreshold: 500 + } + }).on("all", () => { + calback(); }); } - - orderTemplatesGroups(templates:BadgedGroupSelectOption[]): BadgedGroupSelectOption[] { - const compare = (a:BadgedGroupSelectOption|BadgedSelectOption, b:BadgedGroupSelectOption|BadgedSelectOption) => { - return a.label.toString() > b.label.toString() ? 1 : a.label.toString() < b.label.toString() ? -1 : 0 - } - return templates.map( group => { - group.options = group.options.sort((a, b) => compare(a,b)); - return group; - }).sort((a, b) => compare(a,b)); - } } export const createResourceStore = new CreateResourceStore(); diff --git a/src/renderer/components/dock/create-resource.tsx b/src/renderer/components/dock/create-resource.tsx index 34fea2cd86..44210c2c7f 100644 --- a/src/renderer/components/dock/create-resource.tsx +++ b/src/renderer/components/dock/create-resource.tsx @@ -1,20 +1,20 @@ import "./create-resource.scss"; import React from "react"; +import path from "path"; import fs from "fs-extra"; import {Select, GroupSelectOption, SelectOption} from "../select"; import jsYaml from "js-yaml"; import { observable } from "mobx"; import { observer } from "mobx-react"; import { cssNames } from "../../utils"; -import { createResourceStore, BadgedGroupSelectOption } from "./create-resource.store"; +import { createResourceStore } from "./create-resource.store"; import { IDockTab } from "./dock.store"; import { EditorPanel } from "./editor-panel"; import { InfoPanel } from "./info-panel"; import { resourceApplierApi } from "../../api/endpoints/resource-applier.api"; import { JsonApiErrorParsed } from "../../api/json-api"; import { Notifications } from "../notifications"; -import { Badge } from "../badge"; interface Props { className?: string; @@ -30,24 +30,18 @@ export class CreateResource extends React.Component { createResourceStore.watchUserTemplates(()=> { this.templates = []; createResourceStore.getMergedTemplates().then( - badgedTemplates => { - badgedTemplates.map((group) => { - this.templates.push(this.convertBadgedGroup(group)); - }) - }) - }) + templatesDictionary => { + Object.keys(templatesDictionary).forEach(group => { + this.templates.push(this.convertEntryToGroup(group, templatesDictionary[group])); + }); + }); + }); } + convertEntryToGroup(group:string, items:string[]):GroupSelectOption { + const options = items.map(v => ({label: path.parse(v).name, value: v})); - convertBadgedGroup(badgedGroup: BadgedGroupSelectOption):GroupSelectOption { - const options = badgedGroup.options.map(({label, badge, value }) => ({ - label: this.renderSelectOption(label.toString(), badge), - value, - })); - return ({ - label: this.renderSelectGroup(badgedGroup.label.toString(), badgedGroup.badge), - options - }); + return {label: group, options}; } get tabId() { @@ -99,23 +93,6 @@ export class CreateResource extends React.Component { return successMessage; }; - renderSelectOption(label: string, badge?: string){ - return this.renderSelectItem(label,"select-template-option", badge ); - } - - renderSelectGroup(label: string, badge?: string){ - return this.renderSelectItem(label,"select-template-group", badge ); - } - - renderSelectItem(label: string, className: string, badge?: string) { - return( -
- {label} - {badge && } -
- ); - } - renderControls(){ return (
diff --git a/templates/create-resource/ClusterRole.yaml b/templates/create-resource/ClusterRole.yaml new file mode 100644 index 0000000000..0e66a6ada0 --- /dev/null +++ b/templates/create-resource/ClusterRole.yaml @@ -0,0 +1,198 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: read-all-clusterrole +rules: + - nonResourceURLs: + - /metrics + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - bindings + - componentstatuses + - configmaps + - endpoints + - events + - limitranges + - namespaces + - namespaces/finalize + - namespaces/status + - nodes + - nodes/proxy + - nodes/status + - persistentvolumeclaims + - persistentvolumeclaims/status + - persistentvolumes + - persistentvolumes/status + - pods + - pods/attach + - pods/binding + - pods/eviction + - pods/exec + - pods/log + - pods/proxy + - pods/status + - podtemplates + - replicationcontrollers + - replicationcontrollers/scale + - replicationcontrollers/status + - resourcequotas + - resourcequotas/status + - serviceaccounts + - services + - services/proxy + - services/status + verbs: + - get + - list + - watch + - apiGroups: + - apps + resources: + - controllerrevisions + - daemonsets + - daemonsets/status + - deployments + - deployments/scale + - deployments/status + - replicasets + - replicasets/scale + - replicasets/status + - statefulsets + - statefulsets/scale + - statefulsets/status + verbs: + - list + - get + - watch + - apiGroups: + - batch + resources: + - jobs + - jobs/status + verbs: + - get + - list + - watch + - apiGroups: + - autoscaling + resources: + - horizontalpodautoscalers + - horizontalpodautoscalers/status + verbs: + - get + - list + - watch + - apiGroups: + - storage.k8s.io + resources: + - csidrivers + - csinodes + - storageclasses + - volumeattachments + - volumeattachments/status + verbs: + - get + - list + - watch + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - get + - list + - watch + - apiGroups: + - scheduling.k8s.io + resources: + - priorityclasses + verbs: + - get + - list + - watch + - apiGroups: + - node.k8s.io + resources: + - runtimeclasses + verbs: + - get + - list + - watch + - apiGroups: + - extensions + resources: + - ingresses + - ingresses/status + verbs: + - get + - list + - watch + - apiGroups: + - events.k8s.io + resources: + - events + verbs: + - get + - list + - watch + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + - customresourcedefinitions/status + verbs: + - get + - list + - watch + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + - apiservices/status + verbs: + - get + - list + - watch + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch + - apiGroups: + - metrics.k8s.io + resources: + - pods + - nodes + verbs: + - get + - list + - watch + - apiGroups: + - policy + resources: + - poddisruptionbudgets + - poddisruptionbudgets/status + - podsecuritypolicies + verbs: + - get + - list + - watch + - apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + - clusterroles + - rolebindings + - roles + verbs: + - get + - list + - watch diff --git a/templates/create-resource/ClusterRoleBinding.yaml b/templates/create-resource/ClusterRoleBinding.yaml new file mode 100644 index 0000000000..f362a38787 --- /dev/null +++ b/templates/create-resource/ClusterRoleBinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: developer-read-all +subjects: +- kind: ServiceAccount + name: developer + namespace: default +roleRef: + kind: ClusterRole + name: read-all-clusterrole + apiGroup: rbac.authorization.k8s.io diff --git a/templates/create-resource/configuration/ConfigMap.yaml b/templates/create-resource/ConfigMap.yaml similarity index 100% rename from templates/create-resource/configuration/ConfigMap.yaml rename to templates/create-resource/ConfigMap.yaml diff --git a/templates/create-resource/k8s-workloads/CronJob.yaml b/templates/create-resource/CronJob.yaml similarity index 100% rename from templates/create-resource/k8s-workloads/CronJob.yaml rename to templates/create-resource/CronJob.yaml diff --git a/templates/create-resource/k8s-workloads/DeamonSet.yaml b/templates/create-resource/DeamonSet.yaml similarity index 100% rename from templates/create-resource/k8s-workloads/DeamonSet.yaml rename to templates/create-resource/DeamonSet.yaml diff --git a/templates/create-resource/k8s-workloads/Deployment.yaml b/templates/create-resource/Deployment.yaml similarity index 100% rename from templates/create-resource/k8s-workloads/Deployment.yaml rename to templates/create-resource/Deployment.yaml diff --git a/templates/create-resource/networking/Ingress.yaml b/templates/create-resource/Ingress.yaml similarity index 100% rename from templates/create-resource/networking/Ingress.yaml rename to templates/create-resource/Ingress.yaml diff --git a/templates/create-resource/k8s-workloads/Job.yaml b/templates/create-resource/Job.yaml similarity index 100% rename from templates/create-resource/k8s-workloads/Job.yaml rename to templates/create-resource/Job.yaml diff --git a/templates/create-resource/networking/NetworkPolicy.yaml b/templates/create-resource/NetworkPolicy.yaml similarity index 100% rename from templates/create-resource/networking/NetworkPolicy.yaml rename to templates/create-resource/NetworkPolicy.yaml diff --git a/templates/create-resource/storage/PersistentVolume.yaml b/templates/create-resource/PersistentVolume.yaml similarity index 100% rename from templates/create-resource/storage/PersistentVolume.yaml rename to templates/create-resource/PersistentVolume.yaml diff --git a/templates/create-resource/storage/PersistentVolumeClaim.yaml b/templates/create-resource/PersistentVolumeClaim.yaml similarity index 100% rename from templates/create-resource/storage/PersistentVolumeClaim.yaml rename to templates/create-resource/PersistentVolumeClaim.yaml diff --git a/templates/create-resource/k8s-workloads/ReplicaSet.yaml b/templates/create-resource/ReplicaSet.yaml similarity index 100% rename from templates/create-resource/k8s-workloads/ReplicaSet.yaml rename to templates/create-resource/ReplicaSet.yaml diff --git a/templates/create-resource/k8s-workloads/ReplicationController.yaml b/templates/create-resource/ReplicationController.yaml similarity index 100% rename from templates/create-resource/k8s-workloads/ReplicationController.yaml rename to templates/create-resource/ReplicationController.yaml diff --git a/templates/create-resource/access-control/Role.yaml b/templates/create-resource/Role.yaml similarity index 100% rename from templates/create-resource/access-control/Role.yaml rename to templates/create-resource/Role.yaml diff --git a/templates/create-resource/access-control/RoleBinding.yaml b/templates/create-resource/RoleBinding.yaml similarity index 100% rename from templates/create-resource/access-control/RoleBinding.yaml rename to templates/create-resource/RoleBinding.yaml diff --git a/templates/create-resource/configuration/Secret.yaml b/templates/create-resource/Secret.yaml similarity index 100% rename from templates/create-resource/configuration/Secret.yaml rename to templates/create-resource/Secret.yaml diff --git a/templates/create-resource/networking/Service.yaml b/templates/create-resource/Service.yaml similarity index 100% rename from templates/create-resource/networking/Service.yaml rename to templates/create-resource/Service.yaml diff --git a/templates/create-resource/k8s-workloads/StatefulSet.yaml b/templates/create-resource/StatefulSet.yaml similarity index 100% rename from templates/create-resource/k8s-workloads/StatefulSet.yaml rename to templates/create-resource/StatefulSet.yaml diff --git a/templates/create-resource/access-control/ClusterRole.yaml b/templates/create-resource/access-control/ClusterRole.yaml deleted file mode 100644 index 4b4f2afcce..0000000000 --- a/templates/create-resource/access-control/ClusterRole.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - # "namespace" omitted since ClusterRoles are not namespaced - name: secret-reader -rules: -- apiGroups: [""] - # - # at the HTTP level, the name of the resource for accessing Secret - # objects is "secrets" - resources: ["secrets"] - verbs: ["get", "watch", "list"] diff --git a/templates/create-resource/access-control/ClusterRoleBinding.yaml b/templates/create-resource/access-control/ClusterRoleBinding.yaml deleted file mode 100644 index 3887326c41..0000000000 --- a/templates/create-resource/access-control/ClusterRoleBinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace. -kind: ClusterRoleBinding -metadata: - name: read-secrets-global -subjects: -- kind: Group - name: manager # Name is case sensitive - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: secret-reader - apiGroup: rbac.authorization.k8s.io diff --git a/yarn.lock b/yarn.lock index dc2b2715bc..bb17292eb5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2924,7 +2924,7 @@ bluebird-lst@^1.0.9: dependencies: bluebird "^3.5.5" -bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: +bluebird@^3.4.7, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -5690,7 +5690,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: +extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -5840,6 +5840,15 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" +file-js@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/file-js/-/file-js-0.3.0.tgz#fab46bf782346c9294499f1f0d2ad07d838f25d1" + integrity sha1-+rRr94I0bJKUSZ8fDSrQfYOPJdE= + dependencies: + bluebird "^3.4.7" + minimatch "^3.0.3" + proper-lockfile "^1.2.0" + file-loader@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.0.0.tgz#97bbfaab7a2460c07bcbd72d3a6922407f67649f" @@ -5853,6 +5862,18 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +filehound@^1.17.4: + version "1.17.4" + resolved "https://registry.yarnpkg.com/filehound/-/filehound-1.17.4.tgz#3f5b76c5b3edc1080311ba802e1ad43179e4291e" + integrity sha512-A74hiTADH20bpFbXBNyKtpqN4Guffa+ROmdGJWNnuCRhaD45UVSVoI6McLcpHYmuaOERrzD3gMV3v9VZq/SHeA== + dependencies: + bluebird "^3.5.1" + file-js "0.3.0" + lodash "^4.17.10" + minimatch "^3.0.4" + moment "^2.22.1" + unit-compare "^1.0.1" + filelist@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.1.tgz#f10d1a3ae86c1694808e8f20906f43d4c9132dbb" @@ -9527,6 +9548,11 @@ moment@^2.10.2, moment@^2.26.0: resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a" integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw== +moment@^2.14.1, moment@^2.22.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" + integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + moo-color@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/moo-color/-/moo-color-1.0.2.tgz#837c40758d2d58763825d1359a84e330531eca64" @@ -11250,6 +11276,16 @@ prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.8.1" +proper-lockfile@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-1.2.0.tgz#ceff5dd89d3e5f10fb75e1e8e76bc75801a59c34" + integrity sha1-zv9d2J0+XxD7deHo52vHWAGlnDQ= + dependencies: + err-code "^1.0.0" + extend "^3.0.0" + graceful-fs "^4.1.2" + retry "^0.10.0" + proper-lockfile@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.1.tgz#284cf9db9e30a90e647afad69deb7cb06881262c" @@ -13991,6 +14027,13 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" +unit-compare@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unit-compare/-/unit-compare-1.0.1.tgz#0c7459f0e5bf53637ea873ca3cee18de2eeca386" + integrity sha1-DHRZ8OW/U2N+qHPKPO4Y3i7so4Y= + dependencies: + moment "^2.14.1" + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"