aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json22
-rw-r--r--package.json2
-rw-r--r--src/plugins/naive.plugin.ts2
-rw-r--r--src/tools/crontab-generator/crontab-generator.vue216
-rw-r--r--src/tools/crontab-generator/index.ts11
-rw-r--r--src/tools/index.ts3
6 files changed, 255 insertions, 1 deletions
diff --git a/package-lock.json b/package-lock.json
index a6527e7..452c16d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,8 @@
"@vueuse/head": "^0.7.5",
"bip39": "^3.0.4",
"buffer": "^6.0.3",
+ "cron-validator": "^1.3.1",
+ "cronstrue": "^2.2.0",
"crypto-js": "^4.1.1",
"date-fns": "^2.28.0",
"lodash": "^4.17.21",
@@ -2383,6 +2385,16 @@
"sha.js": "^2.4.8"
}
},
+ "node_modules/cron-validator": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.3.1.tgz",
+ "integrity": "sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A=="
+ },
+ "node_modules/cronstrue": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.2.0.tgz",
+ "integrity": "sha512-oM/ftAvCNIdygVGGfYp8gxrVc81mDSA2mff0kvu6+ehrZhfYPzGHG8DVcFdrRVizjHnzWoFIlgEq6KTM/9lPBw=="
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -9925,6 +9937,16 @@
"sha.js": "^2.4.8"
}
},
+ "cron-validator": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.3.1.tgz",
+ "integrity": "sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A=="
+ },
+ "cronstrue": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.2.0.tgz",
+ "integrity": "sha512-oM/ftAvCNIdygVGGfYp8gxrVc81mDSA2mff0kvu6+ehrZhfYPzGHG8DVcFdrRVizjHnzWoFIlgEq6KTM/9lPBw=="
+ },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
diff --git a/package.json b/package.json
index 2461305..6b66aed 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,8 @@
"@vueuse/head": "^0.7.5",
"bip39": "^3.0.4",
"buffer": "^6.0.3",
+ "cron-validator": "^1.3.1",
+ "cronstrue": "^2.2.0",
"crypto-js": "^4.1.1",
"date-fns": "^2.28.0",
"lodash": "^4.17.21",
diff --git a/src/plugins/naive.plugin.ts b/src/plugins/naive.plugin.ts
index 8b3e009..68d2036 100644
--- a/src/plugins/naive.plugin.ts
+++ b/src/plugins/naive.plugin.ts
@@ -45,9 +45,11 @@ import {
NInputGroupLabel,
NDivider,
NStatistic,
+ NTable,
} from 'naive-ui';
const components = [
+ NTable,
NStatistic,
NDivider,
NInputGroup,
diff --git a/src/tools/crontab-generator/crontab-generator.vue b/src/tools/crontab-generator/crontab-generator.vue
new file mode 100644
index 0000000..a77a3f5
--- /dev/null
+++ b/src/tools/crontab-generator/crontab-generator.vue
@@ -0,0 +1,216 @@
+<template>
+ <n-card>
+ <n-form-item class="cron" :show-label="false" :feedback="cronValidation.message"
+ :validation-status="cronValidation.status">
+ <n-input v-model:value="cron" size="large" placeholder="* * * * *" />
+ </n-form-item>
+ <div class="cron-string">
+ {{ cronString }}
+ </div>
+
+ <n-divider />
+
+ <n-space justify="center">
+
+ <n-form :show-feedback="false" label-width="170" label-placement="left">
+ <n-form-item label="Verbose">
+ <n-switch v-model:value="cronstrueConfig.verbose" />
+ </n-form-item>
+ <n-form-item label="Use 24 hour time format">
+ <n-switch v-model:value="cronstrueConfig.use24HourTimeFormat" />
+ </n-form-item>
+ <n-form-item label="Days start at 0">
+ <n-switch v-model:value="cronstrueConfig.dayOfWeekStartIndexZero" />
+ </n-form-item>
+ </n-form>
+ </n-space>
+ </n-card>
+ <br>
+ <n-card>
+ <pre>
+┌──────────── [optional] seconds (0 - 59)
+| ┌────────── minute (0 - 59)
+| | ┌──────── hour (0 - 23)
+| | | ┌────── day of month (1 - 31)
+| | | | ┌──── month (1 - 12) OR jan,feb,mar,apr ...
+| | | | | ┌── day of week (0 - 6, sunday=0) OR sun,mon ...
+| | | | | |
+* * * * * * command</pre>
+
+
+ <n-table size="small">
+ <thead>
+ <tr>
+ <th class="text-left" scope="col">
+ Symbol
+ </th>
+ <th class="text-left" scope="col">
+ Meaning
+ </th>
+ <th class="text-left" scope="col">
+ Example
+ </th>
+ <th class="text-left" scope="col">
+ Equivalent
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>*</td>
+ <td>Any value</td>
+ <td>
+ <code>* * * *</code>
+ </td>
+ <td>Every minute</td>
+ </tr>
+ <tr>
+ <td>-</td>
+ <td>Range of values</td>
+ <td>
+ <code>1-10 * * *</code>
+ </td>
+ <td>Minutes 1 through 10</td>
+ </tr>
+ <tr>
+ <td>,</td>
+ <td>List of values</td>
+ <td>
+ <code>1,10 * * *</code>
+ </td>
+ <td>At minutes 1 and 10</td>
+ </tr>
+ <tr>
+ <td>/</td>
+ <td>Step values</td>
+ <td>
+ <code>*/10 * * *</code>
+ </td>
+ <td>Every 10 minutes</td>
+ </tr>
+ <tr>
+ <td>@yearly</td>
+ <td>Once every year at midnight of 1 January</td>
+ <td>
+ <code>@yearly</code>
+ </td>
+ <td>0 0 1 1 *</td>
+ </tr>
+ <tr>
+ <td>@annually</td>
+ <td>Same as @yearly</td>
+ <td>
+ <code>@annually</code>
+ </td>
+ <td>0 0 1 1 *</td>
+ </tr>
+ <tr>
+ <td>@monthly</td>
+ <td>Once a month at midnight on the first day</td>
+ <td>
+ <code>@monthly</code>
+ </td>
+ <td>0 0 1 * *</td>
+ </tr>
+ <tr>
+ <td>@weekly</td>
+ <td>Once a week at midnight on Sunday morning</td>
+ <td>
+ <code>@weekly</code>
+ </td>
+ <td>0 0 * * 0</td>
+ </tr>
+ <tr>
+ <td>@daily</td>
+ <td>Once a day at midnight</td>
+ <td>
+ <code>@daily</code>
+ </td>
+ <td>0 0 * * *</td>
+ </tr>
+ <tr>
+ <td>@midnight</td>
+ <td>Same as @daily</td>
+ <td>
+ <code>@midnight</code>
+ </td>
+ <td>0 0 * * *</td>
+ </tr>
+ <tr>
+ <td>@hourly</td>
+ <td>Once an hour at the beginning of the hour</td>
+ <td>
+ <code>@hourly</code>
+ </td>
+ <td>0 * * * *</td>
+ </tr>
+ <tr>
+ <td>@reboot</td>
+ <td>Run at startup</td>
+ <td />
+ <td />
+ </tr>
+ </tbody>
+ </n-table>
+
+ </n-card>
+</template>
+
+<script setup lang="ts">
+import cronstrue from 'cronstrue'
+import { isValidCron } from 'cron-validator'
+import { computed, reactive, ref } from 'vue';
+import { useValidation } from '@/composable/validation';
+
+
+function isCronValid(v: string) {
+ return isValidCron(v, { allowBlankDay: true, alias: true, seconds: true })
+}
+
+const cron = ref('40 * * * *')
+const cronstrueConfig = reactive({
+ verbose: true,
+ dayOfWeekStartIndexZero: true,
+ use24HourTimeFormat: true,
+ throwExceptionOnParseError: true
+})
+
+const cronString = computed(() => {
+ if (isCronValid(cron.value)) {
+ return cronstrue.toString(cron.value, cronstrueConfig)
+ }
+ return ' '
+})
+
+const cronValidation = useValidation({
+ source: cron,
+ rules: [{
+ validator: (value) => isCronValid(value),
+ message: 'This cron is invalid'
+ }]
+})
+</script>
+
+<style lang="less" scoped>
+.cron {
+ text-align: center;
+
+ margin: auto;
+ max-width: 400px;
+ display: block;
+
+ .n-input {
+ font-size: 30px;
+ font-family: monospace;
+ padding: 5px;
+
+ }
+}
+
+.cron-string {
+ text-align: center;
+ font-size: 22px;
+ opacity: 0.8;
+ margin: 5px 0 15px;
+}
+</style> \ No newline at end of file
diff --git a/src/tools/crontab-generator/index.ts b/src/tools/crontab-generator/index.ts
new file mode 100644
index 0000000..5628625
--- /dev/null
+++ b/src/tools/crontab-generator/index.ts
@@ -0,0 +1,11 @@
+import { Alarm } from '@vicons/tabler';
+import type { ITool } from './../Tool';
+
+export const tool: ITool = {
+ name: 'Crontab generator',
+ path: '/crontab-generator',
+ description: 'Validate and generate crontab and get the human readable description of the cron schedule.',
+ keywords: ['crontab', 'generator', 'cronjob', 'cron', 'schedule', 'parse', 'expression', 'year', 'month', 'week', 'day', 'minute', 'second'],
+ component: () => import('./crontab-generator.vue'),
+ icon: Alarm,
+};
diff --git a/src/tools/index.ts b/src/tools/index.ts
index d744353..17f7359 100644
--- a/src/tools/index.ts
+++ b/src/tools/index.ts
@@ -1,6 +1,7 @@
import { LockOpen } from '@vicons/tabler';
import type { ToolCategory } from './Tool';
+import { tool as crontabGenerator } from './crontab-generator';
import { tool as textStatistics } from './text-statistics';
import { tool as tokenGenerator } from './token-generator';
import { tool as hashText } from './hash-text';
@@ -34,7 +35,7 @@ export const toolsByCategory: ToolCategory[] = [
{
name: 'Development',
icon: LockOpen,
- components: [gitMemo, randomPortGenerator],
+ components: [gitMemo, randomPortGenerator, crontabGenerator],
},
{
name: 'Text',