Hello, my name is Nick Gottschlich, and I am the creator of Social Amnesia, an Electron/Vue application to help you delete your reddit and twitter content. One feature of this application is scheduling daily runs:
If you're interested in how this was created, and how to create your own scheduling tool with Electron and Vue (think for an alarm clock, a daily reminder, a message scheduler, etc.), then read on!
--
If you haven't already set up your own Electron/Vue app, there are a few short steps to do that, using the vue CLI (command line interface).
npm install -g @vue/cli
vue create electron-vue-node-scheduler
I like to use class-style component syntax, so to follow along with my code, select "typescript" and "Use class-style component syntax"
cd electron-vue-node-scheduler
vue add electron-builder
Now, let's build prototype a simple component that will act as our user interface. We can use Vue Bootstrap to speed up development.
Install with vue add bootstrap-vue
.
Now, we can start up our app with yarn electron:serve
.
Alright, now we can build the actual component.
--
You new boilerplated Electron/Vue app comes with a convenient HelloWorld.Vue component which we will be modifying to be our scheduler component.
Go ahead and copy paste this code over everything that was in HelloWorld.Vue:
<template>
<div>
<b-time
v-model="value"
locale="en"
@context="onContext"
></b-time>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
export default class HelloWorld extends Vue {}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
The b-time here is the bootstrap-vue time component.
We now have set up an easy to use and good looking time selector component. Go ahead and play around with it:
Great, now let's get the actual time out of this so we can use it for our scheduler.
Here's how you will update your class component:
export default class HelloWorld extends Vue {
value = '';
onContext(context) {
console.log('context value', context.value);
}
data() {
return {
value: this.value,
};
}
}
Now, we are keeping track of the value using Vue's data function and we will get an update through onContext
whenever the time picker is changed by the user:
Great, now we can set up our scheduler. We will use node-schedule for this.
yarn add node-schedule
Then in your add a <code>import schedule from "node-schedule";</code>.</p> <p>Then update your component like so:<br> </p> <div class="highlight"><pre class="highlight javascript"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="nc">Vue</span> <span class="p">{</span> <span class="nx">value</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span> <span class="c1">// eslint-disable-next-line @typescript-eslint/no-empty-function</span> <span class="nx">scheduleJob</span> <span class="o">=</span> <span class="nx">schedule</span><span class="p">.</span><span class="nf">scheduleJob</span><span class="p">(</span><span class="dl">'</span><span class="s1">* * * * *</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{});</span> <span class="nf">onContext</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// get hours and minutes off of something like '19:12:00'</span> <span class="kd">const</span> <span class="nx">hours</span> <span class="o">=</span> <span class="nx">context</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">:</span><span class="dl">'</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span> <span class="kd">const</span> <span class="nx">minutes</span> <span class="o">=</span> <span class="nx">context</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">:</span><span class="dl">'</span><span class="p">)[</span><span class="mi">1</span><span class="p">];</span> <span class="k">this</span><span class="p">.</span><span class="nx">scheduleJob</span><span class="p">.</span><span class="nf">cancel</span><span class="p">();</span> <span class="k">this</span><span class="p">.</span><span class="nx">scheduleJob</span> <span class="o">=</span> <span class="nx">schedule</span><span class="p">.</span><span class="nf">scheduleJob</span><span class="p">(</span> <span class="s2">`</span><span class="p">${</span><span class="nx">minutes</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">00</span><span class="dl">'</span><span class="p">}</span><span class="s2"> </span><span class="p">${</span><span class="nx">hours</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">00</span><span class="dl">'</span><span class="p">}</span><span class="s2"> * * *`</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">job ran on schedule!</span><span class="dl">'</span><span class="p">);</span> <span class="p">},</span> <span class="p">);</span> <span class="p">}</span> <span class="nf">data</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="p">{</span> <span class="na">value</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">value</span><span class="p">,</span> <span class="p">};</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div> <p></p> <p>Okay, this is getting a bit more confusing. Let's break it apart:</p> <p><code>scheduleJob = schedule.scheduleJob('* * * * *', () => {});</code> This creates a local scheduleJob we can reference. We need to keep track of this, because any time the time is updated, we are going to cancel any previously scheduled jobs and create a new scheduled job.</p> <p>If the asterisks are confusing you, that's <a href="https://github.com/node-schedule/node-schedule#cron-style-scheduling">cron-style scheduling</a>:</p> <p><img src="https://dev-to-uploads.s3.amazonaws.com/i/xugukl05tmyvv11oofl6.png" alt="cron style scheduling"/></p> <p>Now, onContext (meaning whenever the user changes the time schedule component), we will get a string in the format of 'HH:MM:SS'. We want to break up this string to get hours, and minutes, which we do with the split function: <code>const hours = context.value.split(':')[0];</code></p> <p>Finally, we <code>cancel</code> the previous scheduled job, and create a new one at the time the user has now decided:</p> <p><img src="https://dev-to-uploads.s3.amazonaws.com/i/60yngargkfuieadba7z1.png" alt="screenshot showing job ran on schedule"/></p> <p>Great, that's it! You now have everything you need to build your own scheduler app! And how cool is this, since it's in electron, it's a native app that will run on Windows, Mac and Linux!</p> <p>Next I would recommend looking into Electron's <a href="https://www.electronjs.org/docs/api/tray">Tray functionality</a> so that you can minimize the app to the tray instead of closing it, so your scheduled job will still run at the right time while the app is running in the background.</p> <p>Here is the <a href="https://github.com/Nick-Gottschlich/electron-vue-node-scheduler">GitHub Repo</a> that you can look at if you want to see the code I used in this post.</p>
Top comments (0)