Skip to content

Commit 09096e9

Browse files
committed
chore: phoenix desktop git clone ux from start project. actual git clone remaining. ui done
1 parent 447606e commit 09096e9

File tree

5 files changed

+193
-6
lines changed

5 files changed

+193
-6
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* GNU AGPL-3.0 License
3+
*
4+
* Copyright (c) 2021 - present core.ai . All rights reserved.
5+
*
6+
* This program is free software: you can redistribute it and/or modify it
7+
* under the terms of the GNU Affero General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
14+
* for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see https://opensource.org/licenses/AGPL-3.0.
18+
*
19+
*/
20+
21+
/*global newProjectExtension, Strings, Metrics*/
22+
/*eslint no-console: 0*/
23+
/*eslint strict: ["error", "global"]*/
24+
/* jshint ignore:start */
25+
26+
function desktopInit() {
27+
const LAST_GIT_CLONE_BASE_DIR = "PH_LAST_GIT_CLONE_BASE_DIR";
28+
let createProjectBtn, websiteURLInput, locationInput;
29+
30+
function _validateGitURL(errors) {
31+
let gitURL = websiteURLInput.value;
32+
if(gitURL){
33+
$(websiteURLInput).removeClass("error-border");
34+
return true;
35+
}
36+
$(websiteURLInput).addClass("error-border");
37+
errors.push(`<span><i class="fas fa-exclamation-triangle" style="color: #f89406"></i>&nbsp;&nbsp;${Strings.ERROR_GIT_URL_INVALID}</span>`);
38+
return false;
39+
}
40+
41+
function _validateProjectLocation(errors) {
42+
let location = locationInput.value;
43+
if( location === Strings.PLEASE_SELECT_A_FOLDER){
44+
$(locationInput).addClass("error-border");
45+
return false;
46+
}
47+
if(locationInput.error){
48+
errors.push(`<span><i class="fas fa-exclamation-triangle" style="color: #f89406"></i>&nbsp;&nbsp;${locationInput.error}</span>`);
49+
$(locationInput).addClass("error-border");
50+
return false;
51+
}
52+
$(locationInput).removeClass("error-border");
53+
return true;
54+
}
55+
56+
function _validate() {
57+
const errors = [];
58+
let isValid = _validateGitURL(errors);
59+
isValid = _validateProjectLocation(errors) && isValid;
60+
$(createProjectBtn).prop('disabled', !isValid);
61+
const $messageDisplay = $("#messageDisplay");
62+
$messageDisplay.html("");
63+
if(!isValid) {
64+
$messageDisplay.html(errors.join("<br>"));
65+
}
66+
return isValid;
67+
}
68+
69+
async function _deduceClonePath(newPath) {
70+
if(!newPath){
71+
newPath = locationInput.originalPath;
72+
}
73+
if(!newPath){
74+
return;
75+
}
76+
const {clonePath, error} = await newProjectExtension.getGitCloneDir(newPath, websiteURLInput.value);
77+
locationInput.fullPath = clonePath;
78+
locationInput.value = window.top.Phoenix.fs.getTauriPlatformPath(clonePath);
79+
locationInput.error = error;
80+
locationInput.originalPath = newPath;
81+
}
82+
83+
function _selectFolder() {
84+
newProjectExtension.showFolderSelect(locationInput.originalPath || "")
85+
.then((newPath)=>{
86+
_deduceClonePath(newPath).then(_validate);
87+
}).catch((err)=>{
88+
console.error("user cancelled or error", err);
89+
});
90+
}
91+
92+
function _createProjectClicked() {
93+
localStorage.setItem(LAST_GIT_CLONE_BASE_DIR, locationInput.originalPath);
94+
//newProjectExtension.gitClone(websiteURLInput.value, locationInput.value);
95+
Metrics.countEvent(Metrics.EVENT_TYPE.NEW_PROJECT, "git.Click", "create");
96+
newProjectExtension.closeDialogue();
97+
}
98+
99+
function initGitProject() {
100+
$(".label-clone").text(Strings.GIT_CLONE_URL);
101+
createProjectBtn = document.getElementById("createProjectBtn");
102+
websiteURLInput = document.getElementById("websiteURLInput");
103+
locationInput = document.getElementById("locationInput");
104+
createProjectBtn.onclick = _createProjectClicked;
105+
$(websiteURLInput).keyup(()=>{
106+
_deduceClonePath().then(_validate);
107+
});
108+
locationInput.value = Strings.PLEASE_SELECT_A_FOLDER;
109+
locationInput.onclick = _selectFolder;
110+
websiteURLInput.value = "https://github.com/phcode-dev/HTML-Starter-Templates.git";
111+
_deduceClonePath(localStorage.getItem(LAST_GIT_CLONE_BASE_DIR)).then(_validate);
112+
}
113+
window.initGitProject = initGitProject;
114+
}
115+
116+
if(window.top.Phoenix.isNativeApp){
117+
desktopInit();
118+
}

src/assets/new-project/assets/js/new-github-project.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,15 @@ function browserInit() {
130130
if(!window.showDirectoryPicker){ // fs access apis not present
131131
$(document.getElementById("projectLocation")).addClass("forced-hidden");
132132
}
133+
$(".label-clone").text(Strings.GIT_REPO_URL);
133134
createProjectBtn = document.getElementById("createProjectBtn");
134135
websiteURLInput = document.getElementById("websiteURLInput");
135136
locationInput = document.getElementById("locationInput");
136137
createProjectBtn.onclick = _createProjectClicked;
137138
$(websiteURLInput).keyup(_validate);
138139
locationInput.value = Strings.PLEASE_SELECT_A_FOLDER;
139140
locationInput.onclick = _selectFolder;
141+
websiteURLInput.value = "https://github.com/phcode-dev/HTML-Starter-Templates";
140142
_validate();
141143
}
142144
window.initGitProject = initGitProject;

src/assets/new-project/new-project-github.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<link rel="stylesheet" href="../../thirdparty/fontawesome/css/all.min.css">
1212
<script src="assets/js/phoenix.js"></script>
1313
<script src="assets/js/new-github-project.js"></script>
14+
<script src="assets/js/new-git-project.js"></script>
1415
<style>
1516
#messageDisplay span {
1617
width: 100%;
@@ -47,12 +48,12 @@
4748

4849
<div class="website-main-content">
4950
<div class="website-detail d-flex align-items-center">
50-
<span class="localize">{{GIT_REPO_URL}}</span>
51-
<input id="websiteURLInput" class="w-100" type="text" name="web-url" value="https://github.com/phcode-dev/HTML-Starter-Templates"/>
51+
<span class="label-clone"></span>
52+
<input id="websiteURLInput" class="w-100" type="text" name="web-url" value="" spellcheck="false" autocomplete="off"/>
5253
</div>
5354
<div id="projectLocation" class="website-detail d-flex align-items-center">
5455
<span class="localize">{{LOCATION}}</span>
55-
<input id="locationInput" class="w-100" type="button" name="web-url" value="">
56+
<input id="locationInput" class="w-100" style="text-wrap: inherit;" type="button" name="web-url" value="">
5657
</div>
5758
<div class="website-detail d-flex align-items-center">
5859
<span></span>

src/extensionsIntegrated/Phoenix/new-project.js

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*
1919
*/
2020

21-
/*global Phoenix*/
21+
/*global path*/
2222

2323
define(function (require, exports, module) {
2424
const Dialogs = require("widgets/Dialogs"),
@@ -376,9 +376,9 @@ define(function (require, exports, module) {
376376
});
377377
}
378378

379-
function showFolderSelect() {
379+
function showFolderSelect(initialPath = "") {
380380
return new Promise((resolve, reject)=>{
381-
FileSystem.showOpenDialog(false, true, Strings.CHOOSE_FOLDER, '', null, function (err, files) {
381+
FileSystem.showOpenDialog(false, true, Strings.CHOOSE_FOLDER, initialPath, null, function (err, files) {
382382
if(err || files.length !== 1){
383383
reject();
384384
return;
@@ -388,6 +388,67 @@ define(function (require, exports, module) {
388388
});
389389
}
390390

391+
function _getGitFolderName(gitURL) {
392+
if (typeof gitURL !== 'string' || !gitURL.trim()) {
393+
return "";
394+
}
395+
// Remove trailing `.git` if it exists and split the URL
396+
const parts = gitURL.replace(/\.git$/, '').split('/');
397+
// Return the last segment as the project folder name
398+
return parts[parts.length - 1];
399+
}
400+
401+
async function _dirExists(fullPath) {
402+
try {
403+
const {entry} = await FileSystem.resolveAsync(fullPath);
404+
return entry.isDirectory;
405+
} catch (e) {
406+
return false;
407+
}
408+
}
409+
410+
/**
411+
* Determines which directory to use for a Git clone operation:
412+
* 1. If the selected directory is empty, returns that directory.
413+
* 2. Otherwise, checks/creates a child directory named after the Git project.
414+
* - If that child directory is (or becomes) empty, returns its entry.
415+
* - If it is not empty, returns null.
416+
*
417+
* @param {string} selectedDir - The full path to the user-selected directory.
418+
* @param {string} gitURL - The Git clone URL (used to derive the child folder name).
419+
* @returns {Promise<{error, }>} error string to show to user and the path to clone.
420+
*/
421+
async function getGitCloneDir(selectedDir, gitURL) {
422+
const selectedDirExists = await _dirExists(selectedDir);
423+
if (!selectedDirExists) {
424+
return {error: Strings.ERROR_GIT_FOLDER_NOT_EXIST, clonePath: selectedDir};
425+
}
426+
427+
const {entry: selectedEntry} = await FileSystem.resolveAsync(selectedDir);
428+
if (await selectedEntry.isEmptyAsync()) {
429+
return {clonePath: selectedDir};
430+
}
431+
432+
// If not empty, compute the child directory path
433+
const folderName = _getGitFolderName(gitURL);
434+
if(!folderName){
435+
return {error: Strings.ERROR_GIT_FOLDER_NOT_EMPTY, clonePath: selectedDir};
436+
}
437+
438+
const childDirPath = path.join(selectedDir, folderName);
439+
const childDirExists = await _dirExists(childDirPath);
440+
if (!childDirExists) {
441+
return {clonePath: childDirPath};
442+
}
443+
// The child directory exists; check if it is empty
444+
const {entry: childEntry} = await FileSystem.resolveAsync(childDirPath);
445+
const isChildEmpty = await childEntry.isEmptyAsync();
446+
if(isChildEmpty){
447+
return {clonePath: childDirPath};
448+
}
449+
return {error: Strings.ERROR_GIT_FOLDER_NOT_EMPTY, clonePath: childDirPath};
450+
}
451+
391452
function showAboutBox() {
392453
CommandManager.execute(Commands.HELP_ABOUT);
393454
}
@@ -398,6 +459,7 @@ define(function (require, exports, module) {
398459
exports.downloadAndOpenProject = downloadAndOpenProject;
399460
exports.showFolderSelect = showFolderSelect;
400461
exports.showErrorDialogue = showErrorDialogue;
462+
exports.getGitCloneDir = getGitCloneDir;
401463
exports.setupExploreProject = defaultProjects.setupExploreProject;
402464
exports.setupStartupProject = defaultProjects.setupStartupProject;
403465
exports.alreadyExists = window.Phoenix.VFS.existsAsync;

src/nls/root/strings.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,13 +1187,17 @@ define({
11871187
"GIT_PROJECT": "Get from Git",
11881188
"NEW_PROJECT_FROM_GIT": "New Project from Git",
11891189
"GIT_REPO_URL": "Git Repo URL :",
1190+
"GIT_CLONE_URL": "Git Clone URL :",
11901191
"START_PROJECT": "Start Project\u2026",
11911192
"DOWNLOAD_DESKTOP_APP": "Download Desktop App",
11921193
"GET_DESKTOP_APP": "Get Desktop App",
11931194
"CREATE_PROJECT": "Create Project",
11941195
"SETTING_UP_PROJECT": "Setting Up Project",
11951196
"LOCATION": "Location :",
11961197
"ERROR_ONLY_GITHUB": "The browser version of {APP_NAME} supports only GitHub URLs. To work with other Git URLs, please use the desktop app.",
1198+
"ERROR_GIT_URL_INVALID": "Please enter a valid Git clone URL.",
1199+
"ERROR_GIT_FOLDER_NOT_EMPTY": "The Selected folder cannot be used for Git clone as it is not empty or is unreadable.",
1200+
"ERROR_GIT_FOLDER_NOT_EXIST": "The Selected folder cannot be used for Git clone as it does not exist.",
11971201
"DOWNLOADING": "Downloading...",
11981202
"DOWNLOADING_FILE": "Downloading {0}...",
11991203
"EXTRACTING_FILES_PROGRESS": "Extracting {0} of {1} files.",

0 commit comments

Comments
 (0)