diff --git a/admin/api/repositories.go b/admin/api/repositories.go
index 70986aba..9afaea5d 100644
--- a/admin/api/repositories.go
+++ b/admin/api/repositories.go
@@ -41,5 +41,27 @@ func declareRepositoriesRoutes(router *gin.RouterGroup) {
}
c.JSON(http.StatusOK, mod)
})
+
+ router.DELETE("/repositories/*repopath", func(c *gin.Context) {
+ di, ok := sync.GlobalImporter.(sync.DeletableImporter)
+ if !ok {
+ c.AbortWithStatusJSON(http.StatusNotImplemented, gin.H{"errmsg": "Not implemented"})
+ return
+ }
+
+ if strings.Contains(c.Param("repopath"), "..") {
+ c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Repopath contains invalid characters"})
+ return
+ }
+
+ repopath := strings.TrimPrefix(c.Param("repopath"), "/")
+
+ err := di.DeleteDir(repopath)
+ if err != nil {
+ c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
+ return
+ }
+ c.JSON(http.StatusOK, true)
+ })
}
}
diff --git a/admin/api/settings.go b/admin/api/settings.go
index 60065c3c..0ea7f0ea 100644
--- a/admin/api/settings.go
+++ b/admin/api/settings.go
@@ -8,7 +8,6 @@ import (
"net/http"
"os"
"path"
- "reflect"
"strconv"
"time"
@@ -26,7 +25,6 @@ func declareSettingsRoutes(router *gin.RouterGroup) {
router.GET("/challenge.json", getChallengeInfo)
router.PUT("/challenge.json", saveChallengeInfo)
- router.GET("/settings-ro.json", getROSettings)
router.GET("/settings.json", getSettings)
router.PUT("/settings.json", saveSettings)
router.DELETE("/settings.json", func(c *gin.Context) {
@@ -98,24 +96,6 @@ func fullGeneration(c *gin.Context) {
})
}
-func getROSettings(c *gin.Context) {
- syncMtd := "Disabled"
- if sync.GlobalImporter != nil {
- syncMtd = sync.GlobalImporter.Kind()
- }
-
- var syncId *string
- if sync.GlobalImporter != nil {
- syncId = sync.GlobalImporter.Id()
- }
-
- c.JSON(http.StatusOK, gin.H{
- "sync-type": reflect.TypeOf(sync.GlobalImporter).Name(),
- "sync-id": syncId,
- "sync": syncMtd,
- })
-}
-
func GetChallengeInfo() (*settings.ChallengeInfo, error) {
var challengeinfo string
var err error
diff --git a/admin/api/sync.go b/admin/api/sync.go
index 113524c8..47bfaaad 100644
--- a/admin/api/sync.go
+++ b/admin/api/sync.go
@@ -7,6 +7,7 @@ import (
"net/url"
"os"
"path"
+ "reflect"
"strings"
"srs.epita.fr/fic-server/admin/generation"
@@ -17,6 +18,8 @@ import (
"go.uber.org/multierr"
)
+var lastSyncError = ""
+
func flatifySyncErrors(errs error) (ret []string) {
for _, err := range multierr.Errors(errs) {
ret = append(ret, err.Error())
@@ -27,12 +30,37 @@ func flatifySyncErrors(errs error) (ret []string) {
func declareSyncRoutes(router *gin.RouterGroup) {
apiSyncRoutes := router.Group("/sync")
+ // Return the global sync status
+ apiSyncRoutes.GET("/status", func(c *gin.Context) {
+ syncMtd := "Disabled"
+ if sync.GlobalImporter != nil {
+ syncMtd = sync.GlobalImporter.Kind()
+ }
+
+ var syncId *string
+ if sync.GlobalImporter != nil {
+ syncId = sync.GlobalImporter.Id()
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "sync-type": reflect.TypeOf(sync.GlobalImporter).Name(),
+ "sync-id": syncId,
+ "sync": syncMtd,
+ "pullMutex": !sync.OneGitPullStatus(),
+ "syncMutex": !sync.OneDeepSyncStatus() && !sync.OneThemeDeepSyncStatus(),
+ "progress": sync.DeepSyncProgress,
+ "lastError": lastSyncError,
+ })
+ })
+
// Base sync checks if the local directory is in sync with remote one.
apiSyncRoutes.POST("/base", func(c *gin.Context) {
err := sync.GlobalImporter.Sync()
if err != nil {
+ lastSyncError = err.Error()
c.JSON(http.StatusExpectationFailed, gin.H{"errmsg": err.Error()})
} else {
+ lastSyncError = ""
c.JSON(http.StatusOK, true)
}
})
@@ -45,15 +73,10 @@ func declareSyncRoutes(router *gin.RouterGroup) {
})
// Deep sync: a fully recursive synchronization (can be limited by theme).
- apiSyncRoutes.GET("/deep", func(c *gin.Context) {
- if sync.DeepSyncProgress == 0 {
- c.AbortWithStatusJSON(http.StatusTooEarly, gin.H{"errmsg": "Pas de synchronisation en cours"})
- return
- }
- c.JSON(http.StatusOK, gin.H{"progress": sync.DeepSyncProgress})
- })
apiSyncRoutes.POST("/deep", func(c *gin.Context) {
- c.JSON(http.StatusOK, sync.SyncDeep(sync.GlobalImporter))
+ r := sync.SyncDeep(sync.GlobalImporter)
+ lastSyncError = ""
+ c.JSON(http.StatusOK, r)
})
apiSyncDeepRoutes := apiSyncRoutes.Group("/deep/:thid")
@@ -66,6 +89,7 @@ func declareSyncRoutes(router *gin.RouterGroup) {
}
sync.EditDeepReport(&sync.SyncReport{Exercices: st}, false)
sync.DeepSyncProgress = 255
+ lastSyncError = ""
c.JSON(http.StatusOK, st)
})
apiSyncDeepRoutes.POST("", func(c *gin.Context) {
@@ -79,6 +103,7 @@ func declareSyncRoutes(router *gin.RouterGroup) {
}
sync.EditDeepReport(&sync.SyncReport{Themes: map[string][]string{theme.Name: st}}, false)
sync.DeepSyncProgress = 255
+ lastSyncError = ""
c.JSON(http.StatusOK, st)
})
@@ -90,6 +115,7 @@ func declareSyncRoutes(router *gin.RouterGroup) {
apiSyncRoutes.POST("/themes", func(c *gin.Context) {
_, errs := sync.SyncThemes(sync.GlobalImporter)
+ lastSyncError = ""
c.JSON(http.StatusOK, flatifySyncErrors(errs))
})
diff --git a/admin/static/js/app.js b/admin/static/js/app.js
index 0039770e..77b9c2cd 100644
--- a/admin/static/js/app.js
+++ b/admin/static/js/app.js
@@ -230,9 +230,6 @@ angular.module("FICApp")
.factory("File", function ($resource) {
return $resource("api/files/:fileId", { fileId: '@id' })
})
- .factory("ROSettings", function ($resource) {
- return $resource("api/settings-ro.json")
- })
.factory("Settings", function ($resource) {
return $resource("api/settings.json", null, {
'update': { method: 'PUT' },
@@ -755,6 +752,12 @@ angular.module("FICApp")
$http.get("api/repositories").then(function (response) {
$scope.repositories = response.data.repositories;
});
+
+ $scope.deleteRepository = function(repo) {
+ $http.delete("api/repositories/" + repo.path).then(function (response) {
+ $scope.repositories[$scope.repositories.indexOf(repo)].hash = "- DELETED -";
+ });
+ };
})
.component('repositoryUptodate', {
bindings: {
@@ -781,9 +784,8 @@ angular.module("FICApp")
template: `{{ $ctrl.status.hash }} {{ $ctrl.status.text }}`
})
- .controller("SyncController", function ($scope, $rootScope, ROSettings, $location, $http, $interval) {
+ .controller("SyncController", function ($scope, $rootScope, $location, $http, $interval) {
$scope.displayDangerousActions = false;
- $scope.configro = ROSettings.get();
var needRefreshSyncReportWhenReady = false;
var refreshSyncReport = function () {
@@ -794,30 +796,28 @@ angular.module("FICApp")
};
refreshSyncReport()
+ $scope.deepSyncInProgress = false;
+
var progressInterval = $interval(function () {
- $http.get("api/sync/deep").then(function (response) {
+ $http.get("api/sync/status").then(function (response) {
if (response.data.progress && response.data.progress != 255)
needRefreshSyncReportWhenReady = true;
else if (needRefreshSyncReportWhenReady)
refreshSyncReport();
if (response.data && response.data.progress) {
$scope.syncPercent = Math.floor(response.data.progress * 100 / 255);
- $scope.syncProgress = Math.floor(response.data.progress * 100 / 255) + " %";
+ $scope.deepSyncInProgress = response.data.pullMutex && response.data.syncMutex;
} else {
- $scope.syncProgress = response.data;
$scope.syncPercent = 0;
}
+ $scope.syncStatus = response.data;
}, function (response) {
$scope.syncPercent = 0;
- if (response.data && response.data.errmsg)
- $scope.syncProgress = response.data.errmsg;
- else
- $scope.syncProgress = response.data;
+ $scope.syncStatus = response.data;
})
}, 1500);
$scope.$on('$destroy', function () { $interval.cancel(progressInterval); });
- $scope.deepSyncInProgress = false;
$scope.deepSync = function (theme) {
if (theme) {
question = 'Faire une synchronisation intégrale du thème ' + theme.name + ' ?'
diff --git a/admin/static/views/repositories.html b/admin/static/views/repositories.html
index 3946b181..daca48fa 100644
--- a/admin/static/views/repositories.html
+++ b/admin/static/views/repositories.html
@@ -9,16 +9,20 @@
Chemin |
Branche |
- Commit |
- Plus récent |
+ Commit Plus récent |
{{ repository.path }} |
{{ repository.branch }} |
- {{ repository.hash }} |
- |
+
+ {{ repository.hash }}
+
+ |
+
+
+ |
diff --git a/admin/static/views/sync.html b/admin/static/views/sync.html
index 847c9969..3643d4d5 100644
--- a/admin/static/views/sync.html
+++ b/admin/static/views/sync.html
@@ -32,17 +32,25 @@
- Type
-
+
- Synchronisation
-
- - ID
- - {{ configro['sync-id'] }}
- - Statut
- - {{ syncProgress }}
+
+ - ID
+ -
+ {{ syncStatus['sync-id'] }}
+
+
+ - Statut
+ -
+ {{ syncPercent }} %
+ Pull
+ Synchronisation
+
-
-
+
{{ syncStatus.lastError }}
+
+
diff --git a/qa/ui/vite.config.js b/qa/ui/vite.config.js
index 87470505..f7d505e3 100644
--- a/qa/ui/vite.config.js
+++ b/qa/ui/vite.config.js
@@ -2,6 +2,12 @@ import { sveltekit } from '@sveltejs/kit/vite';
/** @type {import('vite').UserConfig} */
const config = {
+ server: {
+ hmr: {
+ port: 10001
+ }
+ },
+
plugins: [sveltekit()]
};