diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ce931c..aa4f065 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,11 @@
# CodeClocker Changelog
-## 1.0.2
+## 1.0.4 - 2025-04-03
+### Added
+- Validate API key input
+- Improve onboarding UX
+
+## 1.0.2 - 2025-04-01
### Added
- Support IntelliJ Platform 2024.3.5
diff --git a/README.md b/README.md
index 2e6c4f7..e45adcc 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
## What's CodeClocker
-CodeClocker automatically tracks coding activity and visualizes it on web dashboard.
+CodeClocker automatically tracks coding activity and visualizes it on [web dashboard on CodeClocker Hub](https://hub.codeclocker.com/).

diff --git a/gradle.properties b/gradle.properties
index 88ed5f9..b8e4cb2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,10 +1,10 @@
# IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html
pluginGroup = com.codeclocker
-pluginName = CodeClocker - IntelliJ IDEA Activity Tracker
+pluginName = CodeClocker
pluginRepositoryUrl = https://github.com/codeclocker/codeclocker-intellij-plugin
# SemVer format -> https://semver.org
-pluginVersion = 1.0.2
+pluginVersion = 1.0.4
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild = 242
diff --git a/src/main/java/com/codeclocker/plugin/intellij/ListenerRegistrator.java b/src/main/java/com/codeclocker/plugin/intellij/ListenerRegistrator.java
index 2035381..b2cfaf1 100644
--- a/src/main/java/com/codeclocker/plugin/intellij/ListenerRegistrator.java
+++ b/src/main/java/com/codeclocker/plugin/intellij/ListenerRegistrator.java
@@ -2,10 +2,10 @@
import static java.awt.AWTEvent.FOCUS_EVENT_MASK;
-import com.codeclocker.plugin.intellij.apikey.ApiKeyActivationCheckerTask;
import com.codeclocker.plugin.intellij.apikey.ApiKeyPromptStartupActivity;
import com.codeclocker.plugin.intellij.listeners.FocusListener;
import com.codeclocker.plugin.intellij.reporting.DataReportingTask;
+import com.codeclocker.plugin.intellij.subscription.SubscriptionStateCheckerTask;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.ProjectActivity;
@@ -51,6 +51,6 @@ private static void startDataReportingTask() {
}
private static void startCheckingApiKeyStatus() {
- ApplicationManager.getApplication().getService(ApiKeyActivationCheckerTask.class).schedule();
+ ApplicationManager.getApplication().getService(SubscriptionStateCheckerTask.class).schedule();
}
}
diff --git a/src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyInputValidator.java b/src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyInputValidator.java
new file mode 100644
index 0000000..381a6a0
--- /dev/null
+++ b/src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyInputValidator.java
@@ -0,0 +1,21 @@
+package com.codeclocker.plugin.intellij.apikey;
+
+import com.intellij.openapi.ui.InputValidator;
+import com.intellij.openapi.util.NlsSafe;
+
+public class ApiKeyInputValidator implements InputValidator {
+
+ @Override
+ public boolean checkInput(@NlsSafe String s) {
+ return isValid(s);
+ }
+
+ @Override
+ public boolean canClose(@NlsSafe String s) {
+ return isValid(s);
+ }
+
+ private static boolean isValid(String apiKey) {
+ return apiKey != null && apiKey.startsWith("cc-") && apiKey.length() == 39;
+ }
+}
diff --git a/src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyPromptStartupActivity.java b/src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyPromptStartupActivity.java
index 426a6d0..3f6525d 100644
--- a/src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyPromptStartupActivity.java
+++ b/src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyPromptStartupActivity.java
@@ -1,23 +1,12 @@
package com.codeclocker.plugin.intellij.apikey;
-import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationManager;
public class ApiKeyPromptStartupActivity {
- private static final String FIRST_LAUNCH_PROPERTY = "com.codeclocker.first-launch";
-
public static void showApiKeyDialog() {
- PropertiesComponent properties = PropertiesComponent.getInstance();
- boolean prompt = properties.getBoolean("com.codeclocker.prompt-for-api-key", true);
-
- if (ApiKeyPersistence.getApiKey() == null && prompt) {
- ApplicationManager.getApplication()
- .invokeLater(
- () -> {
- EnterApiKeyAction.showAction();
- properties.setValue(FIRST_LAUNCH_PROPERTY, false);
- });
+ if (ApiKeyPersistence.getApiKey() == null) {
+ ApplicationManager.getApplication().invokeLater(EnterApiKeyAction::showAction);
}
}
}
diff --git a/src/main/java/com/codeclocker/plugin/intellij/apikey/EnterApiKeyAction.java b/src/main/java/com/codeclocker/plugin/intellij/apikey/EnterApiKeyAction.java
index e0b6590..298ba60 100644
--- a/src/main/java/com/codeclocker/plugin/intellij/apikey/EnterApiKeyAction.java
+++ b/src/main/java/com/codeclocker/plugin/intellij/apikey/EnterApiKeyAction.java
@@ -3,6 +3,7 @@
import static com.codeclocker.plugin.intellij.HubHost.HUB_UI_HOST;
import static org.apache.commons.lang3.StringUtils.isBlank;
+import com.codeclocker.plugin.intellij.subscription.SubscriptionStateCheckerTask;
import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -23,14 +24,14 @@ public static void showAction() {
Messages.showYesNoCancelDialog(
text,
"Enter CodeClocker API Key",
- "I Have API Key",
"Get API Key",
+ "I Have API Key",
"Cancel",
Messages.getInformationIcon());
- if (result == Messages.YES) {
+ if (result == Messages.NO) {
showApiKeyInputDialog();
- } else if (result == Messages.NO) {
+ } else if (result == Messages.YES) {
BrowserUtil.browse(HUB_UI_HOST + "/api-key");
showApiKeyInputDialog();
}
@@ -53,8 +54,12 @@ private static String getText() {
private static void showApiKeyInputDialog() {
String apiKey =
Messages.showInputDialog(
- "Enter your API key:", "Activate CodeClocker", Messages.getInformationIcon());
+ "Enter your API key\n\nCopy from: hub.codeclocker.com/api-key",
+ "Activate CodeClocker",
+ Messages.getInformationIcon(),
+ null,
+ new ApiKeyInputValidator());
ApiKeyPersistence.persistApiKey(apiKey);
- ApplicationManager.getApplication().getService(ApiKeyActivationCheckerTask.class).schedule();
+ ApplicationManager.getApplication().getService(SubscriptionStateCheckerTask.class).schedule();
}
}
diff --git a/src/main/java/com/codeclocker/plugin/intellij/reporting/DataReportingTask.java b/src/main/java/com/codeclocker/plugin/intellij/reporting/DataReportingTask.java
index 0c19494..ff635ff 100644
--- a/src/main/java/com/codeclocker/plugin/intellij/reporting/DataReportingTask.java
+++ b/src/main/java/com/codeclocker/plugin/intellij/reporting/DataReportingTask.java
@@ -9,12 +9,12 @@
import static org.apache.commons.lang3.StringUtils.isBlank;
import com.codeclocker.plugin.intellij.apikey.ApiKeyLifecycle;
-import com.codeclocker.plugin.intellij.apikey.CheckApiKeyStateHttpClient;
import com.codeclocker.plugin.intellij.config.ConfigProvider;
import com.codeclocker.plugin.intellij.services.ChangesActivityTracker;
import com.codeclocker.plugin.intellij.services.ChangesSample;
import com.codeclocker.plugin.intellij.services.TimeSpentActivityTracker;
import com.codeclocker.plugin.intellij.services.TimeSpentPerProjectSample;
+import com.codeclocker.plugin.intellij.subscription.CheckSubscriptionStateHttpClient;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
@@ -28,7 +28,7 @@
public final class DataReportingTask implements Disposable {
- private static final Logger LOG = Logger.getInstance(CheckApiKeyStateHttpClient.class);
+ private static final Logger LOG = Logger.getInstance(CheckSubscriptionStateHttpClient.class);
private final int flushToServerFrequencySeconds;
private final TimeSpentActivityTracker timeSpentActivityTracker;
diff --git a/src/main/java/com/codeclocker/plugin/intellij/apikey/CheckApiKeyStateHttpClient.java b/src/main/java/com/codeclocker/plugin/intellij/subscription/CheckSubscriptionStateHttpClient.java
similarity index 82%
rename from src/main/java/com/codeclocker/plugin/intellij/apikey/CheckApiKeyStateHttpClient.java
rename to src/main/java/com/codeclocker/plugin/intellij/subscription/CheckSubscriptionStateHttpClient.java
index 783dfa2..d716519 100644
--- a/src/main/java/com/codeclocker/plugin/intellij/apikey/CheckApiKeyStateHttpClient.java
+++ b/src/main/java/com/codeclocker/plugin/intellij/subscription/CheckSubscriptionStateHttpClient.java
@@ -1,4 +1,4 @@
-package com.codeclocker.plugin.intellij.apikey;
+package com.codeclocker.plugin.intellij.subscription;
import static com.codeclocker.plugin.intellij.HubHost.HUB_API_HOST;
import static com.codeclocker.plugin.intellij.Timeouts.CONNECT_TIMEOUT;
@@ -8,9 +8,9 @@
import com.intellij.util.io.HttpRequests;
import org.jetbrains.annotations.Nullable;
-public class CheckApiKeyStateHttpClient {
+public class CheckSubscriptionStateHttpClient {
- private static final Logger LOG = Logger.getInstance(CheckApiKeyStateHttpClient.class);
+ private static final Logger LOG = Logger.getInstance(CheckSubscriptionStateHttpClient.class);
@Nullable
public String check(String apiKey) {
diff --git a/src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyActivationCheckerTask.java b/src/main/java/com/codeclocker/plugin/intellij/subscription/SubscriptionStateCheckerTask.java
similarity index 75%
rename from src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyActivationCheckerTask.java
rename to src/main/java/com/codeclocker/plugin/intellij/subscription/SubscriptionStateCheckerTask.java
index cbf65dc..336be3c 100644
--- a/src/main/java/com/codeclocker/plugin/intellij/apikey/ApiKeyActivationCheckerTask.java
+++ b/src/main/java/com/codeclocker/plugin/intellij/subscription/SubscriptionStateCheckerTask.java
@@ -1,28 +1,29 @@
-package com.codeclocker.plugin.intellij.apikey;
+package com.codeclocker.plugin.intellij.subscription;
import static com.codeclocker.plugin.intellij.ScheduledExecutor.EXECUTOR;
import static com.codeclocker.plugin.intellij.apikey.ApiKeyLifecycle.continueCollectingActivityData;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.commons.lang3.StringUtils.isBlank;
+import com.codeclocker.plugin.intellij.apikey.ApiKeyPersistence;
import com.codeclocker.plugin.intellij.config.ConfigProvider;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import java.util.concurrent.ScheduledFuture;
-public class ApiKeyActivationCheckerTask implements Disposable {
+public class SubscriptionStateCheckerTask implements Disposable {
- private static final Logger LOG = Logger.getInstance(ApiKeyActivationCheckerTask.class);
+ private static final Logger LOG = Logger.getInstance(SubscriptionStateCheckerTask.class);
private final int checkApiKeyStatusFrequencySeconds;
- private final CheckApiKeyStateHttpClient checkSubscriptionStateByApiKeyHttpClient;
+ private final CheckSubscriptionStateHttpClient checkSubscriptionStateByApiKeyHttpClient;
private ScheduledFuture> task;
- public ApiKeyActivationCheckerTask() {
+ public SubscriptionStateCheckerTask() {
this.checkSubscriptionStateByApiKeyHttpClient =
- ApplicationManager.getApplication().getService(CheckApiKeyStateHttpClient.class);
+ ApplicationManager.getApplication().getService(CheckSubscriptionStateHttpClient.class);
ConfigProvider configProvider =
ApplicationManager.getApplication().getService(ConfigProvider.class);
this.checkApiKeyStatusFrequencySeconds = configProvider.getCheckApiKeyStatusFrequencySeconds();
@@ -35,10 +36,7 @@ public void schedule() {
this.task =
EXECUTOR.scheduleWithFixedDelay(
- this::checkApiKeyState,
- checkApiKeyStatusFrequencySeconds,
- checkApiKeyStatusFrequencySeconds,
- SECONDS);
+ this::checkApiKeyState, 10, checkApiKeyStatusFrequencySeconds, SECONDS);
}
private void checkApiKeyState() {
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 0a5b5c9..70a38cf 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -15,13 +15,13 @@
serviceImplementation="com.codeclocker.plugin.intellij.services.TimeSpentActivityTracker"/>
-
+
+ serviceImplementation="com.codeclocker.plugin.intellij.subscription.SubscriptionStateCheckerTask"/>