mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-08 07:11:03 -04:00
Merge branch 'main' into tools/mac-address-generator
This commit is contained in:
commit
e48fd59cfb
11 changed files with 248 additions and 66 deletions
5
.dockerignore
Normal file
5
.dockerignore
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
node_modules
|
||||||
|
playwright-report
|
||||||
|
coverage
|
||||||
|
dist
|
||||||
|
test-results
|
|
@ -1,13 +1,16 @@
|
||||||
# build stage
|
# build stage
|
||||||
FROM node:lts-alpine AS build-stage
|
FROM node:lts-alpine AS build-stage
|
||||||
|
# Set environment variables for non-interactive npm installs
|
||||||
|
ENV NPM_CONFIG_LOGLEVEL warn
|
||||||
|
ENV CI true
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
RUN npm install -g pnpm && pnpm i --frozen-lockfile
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm install -g pnpm
|
|
||||||
RUN pnpm i --frozen-lockfile
|
|
||||||
RUN pnpm build
|
RUN pnpm build
|
||||||
|
|
||||||
# production stage
|
# production stage
|
||||||
FROM nginx:stable-alpine AS production-stage
|
FROM nginxinc/nginx-unprivileged:stable-alpine AS production-stage
|
||||||
COPY --from=build-stage /app/dist /usr/share/nginx/html
|
COPY --from=build-stage /app/dist /usr/share/nginx/html
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
|
@ -73,6 +73,13 @@ const formats = computed(() => [
|
||||||
label: 'Snakecase:',
|
label: 'Snakecase:',
|
||||||
value: snakeCase(input.value, baseConfig),
|
value: snakeCase(input.value, baseConfig),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Mockingcase:',
|
||||||
|
value: noCase(input.value, baseConfig)
|
||||||
|
.split('')
|
||||||
|
.map((char, index) => (index % 2 === 0 ? char.toUpperCase() : char.toLowerCase()))
|
||||||
|
.join(''),
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const inputLabelAlignmentConfig = {
|
const inputLabelAlignmentConfig = {
|
||||||
|
|
23
src/tools/color-converter/color-converter.e2e.spec.ts
Normal file
23
src/tools/color-converter/color-converter.e2e.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
test.describe('Tool - Color converter', () => {
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto('/color-converter');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Has title', async ({ page }) => {
|
||||||
|
await expect(page).toHaveTitle('Color converter - IT Tools');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Color is converted from its name to other formats', async ({ page }) => {
|
||||||
|
await page.getByTestId('input-name').fill('olive');
|
||||||
|
|
||||||
|
expect(await page.getByTestId('input-name').inputValue()).toEqual('olive');
|
||||||
|
expect(await page.getByTestId('input-hex').inputValue()).toEqual('#808000');
|
||||||
|
expect(await page.getByTestId('input-rgb').inputValue()).toEqual('rgb(128, 128, 0)');
|
||||||
|
expect(await page.getByTestId('input-hsl').inputValue()).toEqual('hsl(60, 100%, 25%)');
|
||||||
|
expect(await page.getByTestId('input-hwb').inputValue()).toEqual('hwb(60 0% 50%)');
|
||||||
|
expect(await page.getByTestId('input-cmyk').inputValue()).toEqual('device-cmyk(0% 0% 100% 50%)');
|
||||||
|
expect(await page.getByTestId('input-lch').inputValue()).toEqual('lch(52.15% 56.81 99.57)');
|
||||||
|
});
|
||||||
|
});
|
13
src/tools/color-converter/color-converter.models.test.ts
Normal file
13
src/tools/color-converter/color-converter.models.test.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { removeAlphaChannelWhenOpaque } from './color-converter.models';
|
||||||
|
|
||||||
|
describe('color-converter models', () => {
|
||||||
|
describe('removeAlphaChannelWhenOpaque', () => {
|
||||||
|
it('remove alpha channel of an hex color when it is opaque (alpha = 1)', () => {
|
||||||
|
expect(removeAlphaChannelWhenOpaque('#000000ff')).toBe('#000000');
|
||||||
|
expect(removeAlphaChannelWhenOpaque('#ffffffFF')).toBe('#ffffff');
|
||||||
|
expect(removeAlphaChannelWhenOpaque('#000000FE')).toBe('#000000FE');
|
||||||
|
expect(removeAlphaChannelWhenOpaque('#00000000')).toBe('#00000000');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
52
src/tools/color-converter/color-converter.models.ts
Normal file
52
src/tools/color-converter/color-converter.models.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { type Colord, colord } from 'colord';
|
||||||
|
import { withDefaultOnError } from '@/utils/defaults';
|
||||||
|
import { useValidation } from '@/composable/validation';
|
||||||
|
|
||||||
|
export { removeAlphaChannelWhenOpaque, buildColorFormat };
|
||||||
|
|
||||||
|
function removeAlphaChannelWhenOpaque(hexColor: string) {
|
||||||
|
return hexColor.replace(/^(#(?:[0-9a-f]{3}){1,2})ff$/i, '$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildColorFormat({
|
||||||
|
label,
|
||||||
|
parse = value => colord(value),
|
||||||
|
format,
|
||||||
|
placeholder,
|
||||||
|
invalidMessage = `Invalid ${label.toLowerCase()} format.`,
|
||||||
|
type = 'text',
|
||||||
|
}: {
|
||||||
|
label: string
|
||||||
|
parse?: (value: string) => Colord
|
||||||
|
format: (value: Colord) => string
|
||||||
|
placeholder?: string
|
||||||
|
invalidMessage?: string
|
||||||
|
type?: 'text' | 'color-picker'
|
||||||
|
}) {
|
||||||
|
const value = ref('');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
label,
|
||||||
|
parse: (v: string) => withDefaultOnError(() => parse(v), undefined),
|
||||||
|
format,
|
||||||
|
placeholder,
|
||||||
|
value,
|
||||||
|
validation: useValidation({
|
||||||
|
source: value,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
message: invalidMessage,
|
||||||
|
validator: v => withDefaultOnError(() => {
|
||||||
|
if (v === '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse(v).isValid();
|
||||||
|
}, false),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,87 +1,103 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { Colord } from 'colord';
|
||||||
import { colord, extend } from 'colord';
|
import { colord, extend } from 'colord';
|
||||||
|
import _ from 'lodash';
|
||||||
import cmykPlugin from 'colord/plugins/cmyk';
|
import cmykPlugin from 'colord/plugins/cmyk';
|
||||||
import hwbPlugin from 'colord/plugins/hwb';
|
import hwbPlugin from 'colord/plugins/hwb';
|
||||||
import namesPlugin from 'colord/plugins/names';
|
import namesPlugin from 'colord/plugins/names';
|
||||||
import lchPlugin from 'colord/plugins/lch';
|
import lchPlugin from 'colord/plugins/lch';
|
||||||
import InputCopyable from '../../components/InputCopyable.vue';
|
import { buildColorFormat } from './color-converter.models';
|
||||||
|
|
||||||
extend([cmykPlugin, hwbPlugin, namesPlugin, lchPlugin]);
|
extend([cmykPlugin, hwbPlugin, namesPlugin, lchPlugin]);
|
||||||
|
|
||||||
const name = ref('');
|
const formats = {
|
||||||
const hex = ref('#1ea54cff');
|
picker: buildColorFormat({
|
||||||
const rgb = ref('');
|
label: 'color picker',
|
||||||
const hsl = ref('');
|
format: (v: Colord) => v.toHex(),
|
||||||
const hwb = ref('');
|
type: 'color-picker',
|
||||||
const cmyk = ref('');
|
}),
|
||||||
const lch = ref('');
|
hex: buildColorFormat({
|
||||||
|
label: 'hex',
|
||||||
|
format: (v: Colord) => v.toHex(),
|
||||||
|
placeholder: 'e.g. #ff0000',
|
||||||
|
}),
|
||||||
|
rgb: buildColorFormat({
|
||||||
|
label: 'rgb',
|
||||||
|
format: (v: Colord) => v.toRgbString(),
|
||||||
|
placeholder: 'e.g. rgb(255, 0, 0)',
|
||||||
|
}),
|
||||||
|
hsl: buildColorFormat({
|
||||||
|
label: 'hsl',
|
||||||
|
format: (v: Colord) => v.toHslString(),
|
||||||
|
placeholder: 'e.g. hsl(0, 100%, 50%)',
|
||||||
|
}),
|
||||||
|
hwb: buildColorFormat({
|
||||||
|
label: 'hwb',
|
||||||
|
format: (v: Colord) => v.toHwbString(),
|
||||||
|
placeholder: 'e.g. hwb(0, 0%, 0%)',
|
||||||
|
}),
|
||||||
|
lch: buildColorFormat({
|
||||||
|
label: 'lch',
|
||||||
|
format: (v: Colord) => v.toLchString(),
|
||||||
|
placeholder: 'e.g. lch(53.24, 104.55, 40.85)',
|
||||||
|
}),
|
||||||
|
cmyk: buildColorFormat({
|
||||||
|
label: 'cmyk',
|
||||||
|
format: (v: Colord) => v.toCmykString(),
|
||||||
|
placeholder: 'e.g. cmyk(0, 100%, 100%, 0)',
|
||||||
|
}),
|
||||||
|
name: buildColorFormat({
|
||||||
|
label: 'name',
|
||||||
|
format: (v: Colord) => v.toName({ closest: true }) ?? 'Unknown',
|
||||||
|
placeholder: 'e.g. red',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
function onInputUpdated(value: string, omit: string) {
|
updateColorValue(colord('#1ea54c'));
|
||||||
try {
|
|
||||||
const color = colord(value);
|
|
||||||
|
|
||||||
if (omit !== 'name') {
|
function updateColorValue(value: Colord | undefined, omitLabel?: string) {
|
||||||
name.value = color.toName({ closest: true }) ?? '';
|
if (value === undefined) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (omit !== 'hex') {
|
|
||||||
hex.value = color.toHex();
|
if (!value.isValid()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (omit !== 'rgb') {
|
|
||||||
rgb.value = color.toRgbString();
|
_.forEach(formats, ({ value: valueRef, format }, key) => {
|
||||||
}
|
if (key !== omitLabel) {
|
||||||
if (omit !== 'hsl') {
|
valueRef.value = format(value);
|
||||||
hsl.value = color.toHslString();
|
|
||||||
}
|
|
||||||
if (omit !== 'hwb') {
|
|
||||||
hwb.value = color.toHwbString();
|
|
||||||
}
|
|
||||||
if (omit !== 'cmyk') {
|
|
||||||
cmyk.value = color.toCmykString();
|
|
||||||
}
|
|
||||||
if (omit !== 'lch') {
|
|
||||||
lch.value = color.toLchString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onInputUpdated(hex.value, 'hex');
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<c-card>
|
<c-card>
|
||||||
<n-form label-width="100" label-placement="left">
|
<template v-for="({ label, parse, placeholder, validation, type }, key) in formats" :key="key">
|
||||||
<n-form-item label="color picker:">
|
<input-copyable
|
||||||
|
v-if="type === 'text'"
|
||||||
|
v-model:value="formats[key].value.value"
|
||||||
|
:test-id="`input-${key}`"
|
||||||
|
:label="`${label}:`"
|
||||||
|
label-position="left"
|
||||||
|
label-width="100px"
|
||||||
|
label-align="right"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:validation="validation"
|
||||||
|
raw-text
|
||||||
|
clearable
|
||||||
|
mt-2
|
||||||
|
@update:value="(v:string) => updateColorValue(parse(v), key)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<n-form-item v-else-if="type === 'color-picker'" :label="`${label}:`" label-width="100" label-placement="left" :show-feedback="false">
|
||||||
<n-color-picker
|
<n-color-picker
|
||||||
v-model:value="hex"
|
v-model:value="formats[key].value.value"
|
||||||
placement="bottom-end"
|
placement="bottom-end"
|
||||||
@update:value="(v: string) => onInputUpdated(v, 'hex')"
|
@update:value="(v:string) => updateColorValue(parse(v), key)"
|
||||||
/>
|
/>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="color name:">
|
</template>
|
||||||
<InputCopyable v-model:value="name" @update:value="(v: string) => onInputUpdated(v, 'name')" />
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="hex:">
|
|
||||||
<InputCopyable v-model:value="hex" @update:value="(v: string) => onInputUpdated(v, 'hex')" />
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="rgb:">
|
|
||||||
<InputCopyable v-model:value="rgb" @update:value="(v: string) => onInputUpdated(v, 'rgb')" />
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="hsl:">
|
|
||||||
<InputCopyable v-model:value="hsl" @update:value="(v: string) => onInputUpdated(v, 'hsl')" />
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="hwb:">
|
|
||||||
<InputCopyable v-model:value="hwb" @update:value="(v: string) => onInputUpdated(v, 'hwb')" />
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="lch:">
|
|
||||||
<InputCopyable v-model:value="lch" @update:value="(v: string) => onInputUpdated(v, 'lch')" />
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="cmyk:">
|
|
||||||
<InputCopyable v-model:value="cmyk" @update:value="(v: string) => onInputUpdated(v, 'cmyk')" />
|
|
||||||
</n-form-item>
|
|
||||||
</n-form>
|
|
||||||
</c-card>
|
</c-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -29,5 +29,6 @@ test.describe('Date time converter - json to yaml', () => {
|
||||||
expect((await page.getByTestId('Timestamp').inputValue()).trim()).toEqual('1681333824000');
|
expect((await page.getByTestId('Timestamp').inputValue()).trim()).toEqual('1681333824000');
|
||||||
expect((await page.getByTestId('UTC format').inputValue()).trim()).toEqual('Wed, 12 Apr 2023 21:10:24 GMT');
|
expect((await page.getByTestId('UTC format').inputValue()).trim()).toEqual('Wed, 12 Apr 2023 21:10:24 GMT');
|
||||||
expect((await page.getByTestId('Mongo ObjectID').inputValue()).trim()).toEqual('64371e400000000000000000');
|
expect((await page.getByTestId('Mongo ObjectID').inputValue()).trim()).toEqual('64371e400000000000000000');
|
||||||
|
expect((await page.getByTestId('Excel date/time').inputValue()).trim()).toEqual('45028.88222222222');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
import {
|
import {
|
||||||
|
dateToExcelFormat,
|
||||||
|
excelFormatToDate,
|
||||||
|
isExcelFormat,
|
||||||
isISO8601DateTimeString,
|
isISO8601DateTimeString,
|
||||||
isISO9075DateString,
|
isISO9075DateString,
|
||||||
isMongoObjectId,
|
isMongoObjectId,
|
||||||
|
@ -139,4 +142,39 @@ describe('date-time-converter models', () => {
|
||||||
expect(isMongoObjectId('')).toBe(false);
|
expect(isMongoObjectId('')).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('isExcelFormat', () => {
|
||||||
|
test('an Excel format string is a floating number that can be negative', () => {
|
||||||
|
expect(isExcelFormat('0')).toBe(true);
|
||||||
|
expect(isExcelFormat('1')).toBe(true);
|
||||||
|
expect(isExcelFormat('1.1')).toBe(true);
|
||||||
|
expect(isExcelFormat('-1.1')).toBe(true);
|
||||||
|
expect(isExcelFormat('-1')).toBe(true);
|
||||||
|
|
||||||
|
expect(isExcelFormat('')).toBe(false);
|
||||||
|
expect(isExcelFormat('foo')).toBe(false);
|
||||||
|
expect(isExcelFormat('1.1.1')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('dateToExcelFormat', () => {
|
||||||
|
test('a date in Excel format is the number of days since 01/01/1900', () => {
|
||||||
|
expect(dateToExcelFormat(new Date('2016-05-20T00:00:00.000Z'))).toBe('42510');
|
||||||
|
expect(dateToExcelFormat(new Date('2016-05-20T12:00:00.000Z'))).toBe('42510.5');
|
||||||
|
expect(dateToExcelFormat(new Date('2023-10-31T09:26:06.421Z'))).toBe('45230.39312987268');
|
||||||
|
expect(dateToExcelFormat(new Date('1970-01-01T00:00:00.000Z'))).toBe('25569');
|
||||||
|
expect(dateToExcelFormat(new Date('1800-01-01T00:00:00.000Z'))).toBe('-36522');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('excelFormatToDate', () => {
|
||||||
|
test('a date in Excel format is the number of days since 01/01/1900', () => {
|
||||||
|
expect(excelFormatToDate('0')).toEqual(new Date('1899-12-30T00:00:00.000Z'));
|
||||||
|
expect(excelFormatToDate('1')).toEqual(new Date('1899-12-31T00:00:00.000Z'));
|
||||||
|
expect(excelFormatToDate('2')).toEqual(new Date('1900-01-01T00:00:00.000Z'));
|
||||||
|
expect(excelFormatToDate('4242.4242')).toEqual(new Date('1911-08-12T10:10:50.880Z'));
|
||||||
|
expect(excelFormatToDate('42738.22626859954')).toEqual(new Date('2017-01-03T05:25:49.607Z'));
|
||||||
|
expect(excelFormatToDate('-1000')).toEqual(new Date('1897-04-04T00:00:00.000Z'));
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,6 +9,9 @@ export {
|
||||||
isTimestamp,
|
isTimestamp,
|
||||||
isUTCDateString,
|
isUTCDateString,
|
||||||
isMongoObjectId,
|
isMongoObjectId,
|
||||||
|
dateToExcelFormat,
|
||||||
|
excelFormatToDate,
|
||||||
|
isExcelFormat,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ISO8601_REGEX
|
const ISO8601_REGEX
|
||||||
|
@ -21,6 +24,8 @@ const RFC3339_REGEX
|
||||||
|
|
||||||
const RFC7231_REGEX = /^[A-Za-z]{3},\s[0-9]{2}\s[A-Za-z]{3}\s[0-9]{4}\s[0-9]{2}:[0-9]{2}:[0-9]{2}\sGMT$/;
|
const RFC7231_REGEX = /^[A-Za-z]{3},\s[0-9]{2}\s[A-Za-z]{3}\s[0-9]{4}\s[0-9]{2}:[0-9]{2}:[0-9]{2}\sGMT$/;
|
||||||
|
|
||||||
|
const EXCEL_FORMAT_REGEX = /^-?\d+(\.\d+)?$/;
|
||||||
|
|
||||||
function createRegexMatcher(regex: RegExp) {
|
function createRegexMatcher(regex: RegExp) {
|
||||||
return (date?: string) => !_.isNil(date) && regex.test(date);
|
return (date?: string) => !_.isNil(date) && regex.test(date);
|
||||||
}
|
}
|
||||||
|
@ -33,6 +38,8 @@ const isUnixTimestamp = createRegexMatcher(/^[0-9]{1,10}$/);
|
||||||
const isTimestamp = createRegexMatcher(/^[0-9]{1,13}$/);
|
const isTimestamp = createRegexMatcher(/^[0-9]{1,13}$/);
|
||||||
const isMongoObjectId = createRegexMatcher(/^[0-9a-fA-F]{24}$/);
|
const isMongoObjectId = createRegexMatcher(/^[0-9a-fA-F]{24}$/);
|
||||||
|
|
||||||
|
const isExcelFormat = createRegexMatcher(EXCEL_FORMAT_REGEX);
|
||||||
|
|
||||||
function isUTCDateString(date?: string) {
|
function isUTCDateString(date?: string) {
|
||||||
if (_.isNil(date)) {
|
if (_.isNil(date)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -45,3 +52,11 @@ function isUTCDateString(date?: string) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dateToExcelFormat(date: Date) {
|
||||||
|
return String(((date.getTime()) / (1000 * 60 * 60 * 24)) + 25569);
|
||||||
|
}
|
||||||
|
|
||||||
|
function excelFormatToDate(excelFormat: string | number) {
|
||||||
|
return new Date((Number(excelFormat) - 25569) * 86400 * 1000);
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,9 @@ import {
|
||||||
} from 'date-fns';
|
} from 'date-fns';
|
||||||
import type { DateFormat, ToDateMapper } from './date-time-converter.types';
|
import type { DateFormat, ToDateMapper } from './date-time-converter.types';
|
||||||
import {
|
import {
|
||||||
|
dateToExcelFormat,
|
||||||
|
excelFormatToDate,
|
||||||
|
isExcelFormat,
|
||||||
isISO8601DateTimeString,
|
isISO8601DateTimeString,
|
||||||
isISO9075DateString,
|
isISO9075DateString,
|
||||||
isMongoObjectId,
|
isMongoObjectId,
|
||||||
|
@ -85,6 +88,12 @@ const formats: DateFormat[] = [
|
||||||
toDate: objectId => new Date(Number.parseInt(objectId.substring(0, 8), 16) * 1000),
|
toDate: objectId => new Date(Number.parseInt(objectId.substring(0, 8), 16) * 1000),
|
||||||
formatMatcher: date => isMongoObjectId(date),
|
formatMatcher: date => isMongoObjectId(date),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Excel date/time',
|
||||||
|
fromDate: date => dateToExcelFormat(date),
|
||||||
|
toDate: excelFormatToDate,
|
||||||
|
formatMatcher: isExcelFormat,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const formatIndex = ref(6);
|
const formatIndex = ref(6);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue