Commit 726f1423 authored by Ayush's avatar Ayush

Add file management UI

parent 1af3a788
...@@ -13,6 +13,7 @@ import {SaveFileComponent} from './save-file/save-file.component'; ...@@ -13,6 +13,7 @@ import {SaveFileComponent} from './save-file/save-file.component';
import {FileComponent} from './file/file.component'; import {FileComponent} from './file/file.component';
import {FileService} from './file.service'; import {FileService} from './file.service';
import { SubmitTryCodeComponent } from './submit-try-code/submit-try-code.component'; import { SubmitTryCodeComponent } from './submit-try-code/submit-try-code.component';
import { FileDirCardComponent } from './file-dir-card/file-dir-card.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
...@@ -23,7 +24,8 @@ import { SubmitTryCodeComponent } from './submit-try-code/submit-try-code.compon ...@@ -23,7 +24,8 @@ import { SubmitTryCodeComponent } from './submit-try-code/submit-try-code.compon
InputComponent, InputComponent,
SaveFileComponent, SaveFileComponent,
FileComponent, FileComponent,
SubmitTryCodeComponent SubmitTryCodeComponent,
FileDirCardComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div id="attempt"> <div id="attempt">
<button id="input" (click)="inputField.setState(true)">Custom Input</button> <button id="input" (click)="inputField.setState(true)">Custom Input</button>
<button id="try" (click)="tryCode(0)" [class.disabled]="compilationError || isCompiling">{{compilationError ? 'Error' : (isCompiling ? 'Compiling...' : 'Try Code')}}</button> <button id="try" (click)="tryCode(0)" [class.disabled]="compilationError || isCompiling">{{compilationError ? 'Error' : (isCompiling ? 'Compiling...' : 'Try Code')}}</button>
<button id="submit" (click)="tryCode(1)" [class.disabled]="compilationError || isCompiling">{{compilationError ? 'Error' : (isCompiling ? 'Compiling...' : 'Try Code')}}</button> <button id="submit" (click)="tryCode(1)" [class.disabled]="compilationError || isCompiling">{{compilationError ? 'Error' : (isCompiling ? 'Compiling...' : 'Submit Code')}}</button>
</div> </div>
<label for="editor"></label> <label for="editor"></label>
<textarea id="editor" name="editor"></textarea> <textarea id="editor" name="editor"></textarea>
......
import {File} from './file';
export interface Directory {
name: string;
dirs: Directory[];
files: File[];
path: string;
}
<div class="card" [style.marginLeft]="level * 20 + 'px'" [style.background]="isFile ? '#002' : '#022'">
<div class="title" *ngIf="isFile">{{file.filename}}{{file.language}}</div>
<div class="title" *ngIf="!isFile">{{directory.name}}</div>
<div class="dir-desc" *ngIf="!isFile">{{directory.dirs.length}} directories, {{directory.files.length}} files</div>
<div *ngIf="isFile"></div>
<div class="file-buttons">
<button (click)="onDelete()" [disabled]="deleting" [class.disabled]="deleting">Delete</button>
<button *ngIf="!isFile" (click)="isExpanded = !isExpanded">{{isExpanded ? 'Collapse' : 'Expand'}}</button>
<button *ngIf="isFile">Edit</button>
<button *ngIf="isFile">Run</button>
</div>
</div>
<div class="subs" *ngIf="!isFile" [style.display]="isExpanded ? 'block' : 'none'">
<app-file-dir-card *ngFor="let dir of directory.dirs" [isFile]="false" [directory]="dir" [level]="level + 1"></app-file-dir-card>
<app-file-dir-card *ngFor="let file of directory.files" [isFile]="true" [file]="file" [level]="level + 1"></app-file-dir-card>
</div>
.card {
display: grid;
grid-template-columns: 33.33% 33.33% 33.33%;
height: 3em;
border-bottom: 1px solid #fff;
button {
float: right;
border: none;
}
.title {
padding: 1em 20px;
}
.dir-desc {
padding: 1.1em 20px;
font-size: 0.8em;
}
.file-buttons {
padding: 0.7em 20px;
}
}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FileDirCardComponent } from './file-dir-card.component';
describe('FileDirCardComponent', () => {
let component: FileDirCardComponent;
let fixture: ComponentFixture<FileDirCardComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FileDirCardComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FileDirCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import {Component, Input, OnInit} from '@angular/core';
import {File} from '../file';
import {Directory} from '../directory';
@Component({
selector: 'app-file-dir-card',
templateUrl: './file-dir-card.component.html',
styleUrls: ['./file-dir-card.component.scss']
})
export class FileDirCardComponent implements OnInit {
@Input() isFile: boolean;
@Input() level: number;
@Input() file: File;
@Input() directory: Directory;
@Input() trace: number[];
deleting: boolean;
isExpanded = false;
constructor() { }
ngOnInit(): void {
}
onDelete(): void {
//
}
}
...@@ -2,7 +2,6 @@ import {Injectable} from '@angular/core'; ...@@ -2,7 +2,6 @@ import {Injectable} from '@angular/core';
import {File} from './file'; import {File} from './file';
import {Observable, of} from 'rxjs'; import {Observable, of} from 'rxjs';
import {HttpClient} from '@angular/common/http'; import {HttpClient} from '@angular/common/http';
import { User } from './user';
@Injectable({ @Injectable({
...@@ -12,7 +11,7 @@ export class FileService { ...@@ -12,7 +11,7 @@ export class FileService {
saveUrl = 'http://localhost/sfcode/backend/filesave.php'; saveUrl = 'http://localhost/sfcode/backend/filesave.php';
uploadUrl = 'http://localhost/sfcode/backend/fileupload.php'; uploadUrl = 'http://localhost/sfcode/backend/fileupload.php';
filelistUrl = 'http://localhost/sfcode/backend/list_files.php' fileListUrl = 'http://localhost/sfcode/backend/dir_tree.php';
deleteUrl = 'http://localhost/sfcode/backend/filedelete.php'; deleteUrl = 'http://localhost/sfcode/backend/filedelete.php';
constructor(private http: HttpClient) { constructor(private http: HttpClient) {
...@@ -45,8 +44,13 @@ export class FileService { ...@@ -45,8 +44,13 @@ export class FileService {
formData.append('file', file, file.name); formData.append('file', file, file.name);
return this.http.post(this.uploadUrl, formData); return this.http.post(this.uploadUrl, formData);
} }
delete(file): Observable<any> { delete(file): Observable<any> {
return this.http.post(this.deleteUrl,file); return this.http.post(this.deleteUrl, file);
}
getFileList(username: string): Observable<any> {
return this.http.post(this.fileListUrl, {username});
} }
} }
import {Directory} from './directory';
export interface File { export interface File {
username: string; username: string;
filename: string; filename: string;
......
...@@ -4,17 +4,11 @@ ...@@ -4,17 +4,11 @@
</div> </div>
<div class="container"> <div class="container">
You have {{files.length}} files stored on the server: {{mainDir.dirs.length}} directories, {{mainDir.files.length}} files:
</div> </div>
<div *ngFor="let file of files" class="card"> <app-file-dir-card *ngFor="let dir of mainDir.dirs" [isFile]="false" [directory]="dir" [level]="0" [trace]="[mainDir.dirs.indexOf(dir)]"></app-file-dir-card>
<span class="title">{{file.filename}}{{file.language}}</span> <app-file-dir-card *ngFor="let file of mainDir.files" [isFile]="true" [file]="file" [level]="0" [trace]="[mainDir.files.indexOf(file)]"></app-file-dir-card>
<button (click)="onDelete()" [disabled]="deleting">Delete</button>
<button>Edit</button>
<button>Run</button>
</div>
<div [class.open]="uploadPopupActive" id="file-upload-cover"></div> <div [class.open]="uploadPopupActive" id="file-upload-cover"></div>
......
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {File} from '../file'; import {File} from '../file';
import {FileService} from '../file.service'; import {FileService} from '../file.service';
import { ApiService } from '../api.service'; import {ApiService} from '../api.service';
import { User } from '../user'; import {User} from '../user';
import {Directory} from '../directory';
@Component({ @Component({
selector: 'app-file', selector: 'app-file',
...@@ -12,15 +13,20 @@ import { User } from '../user'; ...@@ -12,15 +13,20 @@ import { User } from '../user';
export class FileComponent implements OnInit { export class FileComponent implements OnInit {
user: User; user: User;
files: File[]; mainDir: Directory = {
name: '',
files: [],
dirs: [],
path: '/'
};
shortLink = ''; shortLink = '';
loading = false; // Flag variable loading = false; // Flag variable
deleting = false; //Flag variable deleting = false; // Flag variable
fileToUpload: File = null; fileToUpload: File = null;
uploadPopupActive = false; uploadPopupActive = false;
constructor(private fileService: FileService, constructor(private fileService: FileService,
private dataService: ApiService ) { private dataService: ApiService) {
} }
ngOnInit(): void { ngOnInit(): void {
...@@ -29,8 +35,11 @@ export class FileComponent implements OnInit { ...@@ -29,8 +35,11 @@ export class FileComponent implements OnInit {
} }
getFiles(): void { getFiles(): void {
this.fileService.getFiles() this.fileService.getFileList(this.user.username)
.subscribe(files => this.files = files); .subscribe(data => {
this.mainDir = this.toDirectory('', data, '/');
console.log(this.mainDir);
});
} }
onChange(event): void { onChange(event): void {
...@@ -40,7 +49,9 @@ export class FileComponent implements OnInit { ...@@ -40,7 +49,9 @@ export class FileComponent implements OnInit {
onUpload(): void { onUpload(): void {
if ((document.getElementById('file-upload-input') as HTMLInputElement).value === '') {return; } if ((document.getElementById('file-upload-input') as HTMLInputElement).value === '') {
return;
}
this.loading = true; this.loading = true;
console.log(this.fileToUpload); console.log(this.fileToUpload);
...@@ -57,18 +68,47 @@ export class FileComponent implements OnInit { ...@@ -57,18 +68,47 @@ export class FileComponent implements OnInit {
); );
} }
onDelete(file): void { // onDelete(file): void {
this.deleting = true; // this.deleting = true;
this.fileService.delete(file).subscribe( // this.fileService.delete(file).subscribe(
() => { // () => {
this.deleting = false; // this.deleting = false;
this.files.forEach((element,index)=>{ // this.files.forEach((element,index)=>{
if(element==file){ // if(element==file){
this.files.splice(index,1); // this.files.splice(index,1);
} // }
}); // });
//
// }
// );
// }
toDirectory(name: string, obj: any, path: string): Directory {
const ret: Directory = {
name,
dirs: [],
files: [],
path: path === '/' ? path : path + '/'
};
for (const file of obj.files) {
const sp = file.split('.');
const f: File = {
username: this.user.username,
filename: file.replace(/\.[^/.]+$/, ''),
language: '.' + sp[sp.length - 1],
text: '',
path: path + name + '/'
};
ret.files.push(f);
}
for (const dir in obj.dirs) {
if (obj.dirs.hasOwnProperty(dir)) {
ret.dirs.push(this.toDirectory(dir, obj.dirs[dir], ret.path + name));
} }
); }
return ret;
} }
} }
...@@ -59,6 +59,7 @@ button { ...@@ -59,6 +59,7 @@ button {
padding: 5px 10px; padding: 5px 10px;
cursor: pointer; cursor: pointer;
transition: all 0.1s; transition: all 0.1s;
z-index: 1;
&::after { &::after {
z-index: -1; z-index: -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment