Forráskód Böngészése

HUE-9485 [frontend] Add a Vue HumanByteSize component

Johan Ahlen 5 éve
szülő
commit
4bdd836e55

+ 3 - 3
desktop/core/src/desktop/js/components/HueTable.d.ts

@@ -16,12 +16,12 @@
 
 import { Component } from 'vue';
 
-export interface Column {
+export interface Column<T> {
   label: string;
   key: string;
   cellComponent?: Component;
-  cellProps?: (key: string, row: Row) => { [attr: string]: unknown };
-  adapter?: (key: string, row: Row) => string | number | boolean | undefined;
+  cellProps?: (key: string, row: T) => { [attr: string]: unknown };
+  adapter?: (key: string, row: T) => string | number | boolean | undefined;
 }
 
 export type Row = { [key: string]: unknown };

+ 83 - 0
desktop/core/src/desktop/js/components/HumanByteSize.test.ts

@@ -0,0 +1,83 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// 'License'); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { shallowMount } from '@vue/test-utils';
+import HumanByteSize from './HumanByteSize.vue';
+
+describe('HumanByteSize.vue', () => {
+  it('should render', () => {
+    const wrapper = shallowMount(HumanByteSize, {
+      propsData: {
+        value: 10
+      }
+    });
+    expect(wrapper.element).toMatchSnapshot();
+  });
+
+  it('should render 1 B', () => {
+    const wrapper = shallowMount(HumanByteSize, {
+      propsData: {
+        value: 1
+      }
+    });
+    expect(wrapper.element.firstChild?.textContent).toContain('1 B');
+  });
+
+  it('should render 1023 B', () => {
+    const wrapper = shallowMount(HumanByteSize, {
+      propsData: {
+        value: 1023
+      }
+    });
+    expect(wrapper.element.firstChild?.textContent).toContain('1023 B');
+  });
+
+  it('should render 1 KB', () => {
+    const wrapper = shallowMount(HumanByteSize, {
+      propsData: {
+        value: 1024
+      }
+    });
+    expect(wrapper.element.firstChild?.textContent).toContain('1 KB');
+  });
+
+  it('should render 1023 KB', () => {
+    const wrapper = shallowMount(HumanByteSize, {
+      propsData: {
+        value: 1024 * 1023
+      }
+    });
+    expect(wrapper.element.firstChild?.textContent).toContain('1023 KB');
+  });
+
+  it('should render 1 GB', () => {
+    const wrapper = shallowMount(HumanByteSize, {
+      propsData: {
+        value: 1024 * 1024 * 1024
+      }
+    });
+    expect(wrapper.element.firstChild?.textContent).toContain('1 GB');
+  });
+
+  it('should render 1.5 GB', () => {
+    const wrapper = shallowMount(HumanByteSize, {
+      propsData: {
+        value: 1024 * 1024 * 1024 * 1.5
+      }
+    });
+    expect(wrapper.element.firstChild?.textContent).toContain('1.5 GB');
+  });
+});

+ 56 - 0
desktop/core/src/desktop/js/components/HumanByteSize.vue

@@ -0,0 +1,56 @@
+<!--
+  Licensed to Cloudera, Inc. under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  Cloudera, Inc. licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<template>
+  <span>{{ humanSize }}</span>
+</template>
+
+<script lang="ts">
+  import Vue from 'vue';
+  import Component from 'vue-class-component';
+  import { Prop } from 'vue-property-decorator';
+
+  const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB'];
+
+  export const humanSize = (value?: number): string => {
+    if (value === 0) {
+      return '0 B';
+    }
+    if (!value) {
+      return '';
+    }
+    if (value < 1024) {
+      return `${value} B`;
+    }
+    const unitIndex = Math.min(Math.floor(Math.log(value) / Math.log(1024)), UNITS.length - 1);
+    const unitValue = Math.round((value / Math.pow(1024, unitIndex)) * 10) / 10;
+    return `${unitValue} ${UNITS[unitIndex]}`;
+  };
+
+  @Component
+  export default class TimeAgo extends Vue {
+    @Prop({ required: false })
+    value?: number;
+
+    get humanSize(): string {
+      return humanSize(this.value);
+    }
+  }
+</script>
+
+<style lang="scss" scoped></style>

+ 13 - 9
desktop/core/src/desktop/js/components/TimeAgo.vue

@@ -35,6 +35,18 @@
 
   const LIMITS = [YEAR, MONTH, DAY, HOUR, MINUTE, SECOND];
 
+  export const timeAgo = (value: number): string => {
+    const diff = Date.now() - value;
+    for (const limit of LIMITS) {
+      if (diff >= limit.val) {
+        const val = Math.round(diff / limit.val);
+        const postfix = I18n(`${limit.text}${val > 1 ? 's' : ''} ago`);
+        return `${val} ${postfix}`;
+      }
+    }
+    return I18n('now');
+  };
+
   @Component
   export default class TimeAgo extends Vue {
     @Prop({ required: true })
@@ -42,15 +54,7 @@
 
     // TODO: Add timezone support
     get timeAgo(): string {
-      const diff = Date.now() - this.value;
-      for (const limit of LIMITS) {
-        if (diff >= limit.val) {
-          const val = Math.round(diff / limit.val);
-          const postfix = I18n(`${limit.text}${val > 1 ? 's' : ''} ago`);
-          return `${val} ${postfix}`;
-        }
-      }
-      return I18n('now');
+      return timeAgo(this.value);
     }
   }
 </script>

+ 7 - 0
desktop/core/src/desktop/js/components/__snapshots__/HumanByteSize.test.ts.snap

@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`HumanByteSize.vue should render 1`] = `
+<span>
+  10 B
+</span>
+`;