chore: Usability improvements

This commit is contained in:
Robin Shen 2025-10-09 14:10:23 +08:00
parent 0a5860d153
commit 59315b3f81
25 changed files with 422 additions and 227 deletions

View File

@ -655,6 +655,10 @@ public class Build extends ProjectBelonging
public boolean isSuccessful() {
return status == Status.SUCCESSFUL;
}
public boolean isFailed() {
return status == Status.FAILED;
}
public Date getSubmitDate() {
return submitDate;

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1759963509092" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11021" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M1013.775951 516.722584a12.8 12.8 0 0 1-9.322496 9.322495l-198.487702 49.599298a320 320 0 0 0-232.836121 232.836121l-49.644553 198.532957a12.8 12.8 0 0 1-24.844904-0.045255l-49.599298-198.487702a320 320 0 0 0-232.83612-232.836121L17.626545 525.95457a12.8 12.8 0 0 1 0-24.799649l198.532957-49.644553a320 320 0 0 0 232.836121-232.836121L498.640175 20.2318a12.8 12.8 0 0 1 24.844904-0.045255l49.644553 198.532957a320 320 0 0 0 232.836121 232.836121l198.487702 49.599298a12.8 12.8 0 0 1 9.322496 15.567663zM713.374363 513.554745l-9.956064-4.525483a409.792 409.792 0 0 1-187.807561-187.807561l-4.525483-9.956064-4.615993 9.956064a409.792 409.792 0 0 1-187.807561 187.807561l-9.956064 4.525483 10.001319 4.661248a409.792 409.792 0 0 1 187.762306 187.762306l4.570738 9.910809 4.615993-9.865554a409.792 409.792 0 0 1 187.807561-187.807561l9.910809-4.661248z" p-id="11022"></path><path d="M887.453079 38.673217l5.656855 22.763181c11.087434 44.576011 45.888402 79.376979 90.509668 90.509668l22.763181 5.656855a12.8 12.8 0 0 1-0.045255 24.844904l-22.717926 5.702109a124.416 124.416 0 0 0-90.509668 90.509668l-5.702109 22.717926a12.8 12.8 0 0 1-24.79965 0l-5.702109-22.717926a124.416 124.416 0 0 0-90.509668-90.509668l-22.717926-5.702109a12.8 12.8 0 0 1-0.045255-24.844904l22.763181-5.656855c44.576011-11.177944 79.376979-45.978911 90.509668-90.509668l5.656855-22.763181a12.8 12.8 0 0 1 24.890158 0z" p-id="11023"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -13,7 +13,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import org.jspecify.annotations.Nullable;
import javax.inject.Inject;
import javax.servlet.http.Cookie;
@ -53,6 +52,7 @@ import org.apache.wicket.util.time.Duration;
import org.apache.wicket.util.visit.IVisit;
import org.apache.wicket.util.visit.IVisitor;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.jspecify.annotations.Nullable;
import org.unbescape.javascript.JavaScriptEscape;
import com.fasterxml.jackson.core.JsonProcessingException;
@ -65,6 +65,7 @@ import io.onedev.commons.bootstrap.Bootstrap;
import io.onedev.commons.loader.AppLoader;
import io.onedev.server.OneDev;
import io.onedev.server.commandhandler.Upgrade;
import io.onedev.server.event.ListenerRegistry;
import io.onedev.server.model.User;
import io.onedev.server.security.SecurityUtils;
import io.onedev.server.service.AuditService;
@ -82,8 +83,8 @@ import io.onedev.server.web.page.security.LoginPage;
import io.onedev.server.web.page.serverinit.ServerInitPage;
import io.onedev.server.web.page.simple.SimplePage;
import io.onedev.server.web.util.WicketUtils;
import io.onedev.server.web.websocket.WebSocketService;
import io.onedev.server.web.websocket.WebSocketMessages;
import io.onedev.server.web.websocket.WebSocketService;
public abstract class BasePage extends WebPage {
@ -104,6 +105,9 @@ public abstract class BasePage extends WebPage {
@Inject
protected AuditService auditService;
@Inject
protected ListenerRegistry listenerRegistry;
public BasePage(PageParameters params) {
super(params);

View File

@ -8,6 +8,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.persistence.EntityNotFoundException;
import javax.servlet.http.HttpServletResponse;
@ -39,11 +40,11 @@ import com.google.common.collect.Lists;
import edu.emory.mathcs.backport.java.util.Collections;
import io.onedev.server.OneDev;
import io.onedev.server.service.ProjectService;
import io.onedev.server.service.SettingService;
import io.onedev.server.model.Project;
import io.onedev.server.search.entity.project.ProjectQuery;
import io.onedev.server.security.SecurityUtils;
import io.onedev.server.service.ProjectService;
import io.onedev.server.service.SettingService;
import io.onedev.server.timetracking.TimeTrackingService;
import io.onedev.server.util.facade.ProjectFacade;
import io.onedev.server.web.WebConstants;
@ -115,6 +116,9 @@ import io.onedev.server.web.util.ProjectAware;
public abstract class ProjectPage extends LayoutPage implements ProjectAware {
protected final IModel<Project> projectModel;
@Inject
protected ProjectService projectService;
public ProjectPage(PageParameters params) {
super(params);

View File

@ -1,5 +1,6 @@
package io.onedev.server.web.page.project.blob.render.renderers.buildspec;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.FormComponentPanel;
import io.onedev.server.buildspec.BuildSpec;
@ -24,4 +25,9 @@ public class BuildSpecBlobEditPanel extends BlobEditPanel implements PlainEditSu
return new PlainEditPanel(componentId, BuildSpec.BLOB_PATH, initialContent);
}
@Override
protected WebMarkupContainer newEditOptions(String componentId) {
return new BuildSpecEditOptionPanel(componentId);
}
}

View File

@ -0,0 +1,5 @@
<wicket:panel>
<a href="https://docs.onedev.io/tutorials/misc/working-with-mcp" target="_blank">
<wicket:svg href="ai" class="icon"/> Edit with AI
</a>
</wicket:panel>

View File

@ -0,0 +1,11 @@
package io.onedev.server.web.page.project.blob.render.renderers.buildspec;
import org.apache.wicket.markup.html.panel.Panel;
public class BuildSpecEditOptionPanel extends Panel {
public BuildSpecEditOptionPanel(String id) {
super(id);
}
}

View File

@ -106,7 +106,7 @@ public class BuildSpecEditPanel extends FormComponentPanel<byte[]> implements Bu
private void resizeWindow(AjaxRequestTarget target) {
((BasePage)getPage()).resizeWindow(target);
}
@Override
protected void onInitialize() {
super.onInitialize();

View File

@ -1,7 +1,7 @@
<wicket:panel>
<form wicket:id="form" class="upload-blobs">
<div class="modal-header">
<h5 class="modal-title">Upload Files</h5>
<h5 class="modal-title">Upload Artifacts</h5>
<button wicket:id="close" type="button" class="close"><wicket:svg href="times" class="icon"/></button>
</div>
<div class="modal-body">

View File

@ -1,4 +1,4 @@
package io.onedev.server.web.page.project.builds.detail.artifacts;
package io.onedev.server.web.page.project.builds.detail;
import static io.onedev.server.util.IOUtils.BUFFER_SIZE;
import static io.onedev.server.web.translation.Translation._T;

View File

@ -8,10 +8,12 @@
<span wicket:id="statusLabel"></span>
</div>
<div wicket:id="actions" class="mr-2">
<a wicket:id="rebuild" class="btn btn-icon btn-light btn-hover-primary btn-xs mr-2" t:data-tippy-content="Re-run this build"><wicket:svg href="re-run" class="icon"/></a>
<a wicket:id="cancel" class="btn btn-icon btn-light btn-hover-danger btn-xs mr-2" t:data-tippy-content="Cancel this build"><wicket:svg href="cancel" class="icon"/></a>
<a wicket:id="terminal" t:data-tippy-content="Open terminal of current running step" class="subscription-required btn btn-icon btn-light btn-hover-primary btn-xs mr-2"><wicket:svg href="terminal" class="icon"/></a>
<a wicket:id="promotions" class="btn btn-icon btn-light btn-hover-primary btn-xs mr-2" t:data-tippy-content="Promotions"><wicket:svg href="next" class="icon"/></a>
<a wicket:id="rebuild" class="btn btn-icon btn-light btn-hover-primary btn-xs mr-1" t:data-tippy-content="Re-run this build"><wicket:svg href="re-run" class="icon"/></a>
<a wicket:id="cancel" class="btn btn-icon btn-light btn-hover-danger btn-xs mr-1" t:data-tippy-content="Cancel this build"><wicket:svg href="cancel" class="icon"/></a>
<a wicket:id="promotions" class="btn btn-icon btn-light btn-hover-primary btn-xs mr-1" t:data-tippy-content="Promotions"><wicket:svg href="next" class="icon"/></a>
<a wicket:id="setDescription" class="btn btn-icon btn-light btn-hover-primary btn-xs mr-1" t:data-tippy-content="Set description"><wicket:svg href="info" class="icon"/></a>
<a wicket:id="uploadArtifacts" class="btn btn-icon btn-light btn-hover-primary btn-xs mr-1" t:data-tippy-content="Upload artifacts"><wicket:svg href="upload" class="icon"/></a>
<a wicket:id="terminal" t:data-tippy-content="Open terminal of current running step" class="subscription-required btn btn-icon btn-light btn-hover-primary btn-xs mr-1"><wicket:svg href="terminal" class="icon"/></a>
</div>
</div>
<div class="card-toolbar">

View File

@ -8,7 +8,9 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.persistence.EntityNotFoundException;
import org.apache.commons.lang3.StringUtils;
@ -36,14 +38,12 @@ import org.apache.wicket.request.mapper.parameter.PageParameters;
import com.google.common.collect.Sets;
import io.onedev.server.OneDev;
import io.onedev.server.attachment.AttachmentSupport;
import io.onedev.server.buildspec.job.Job;
import io.onedev.server.buildspec.job.JobDependency;
import io.onedev.server.buildspec.param.spec.ParamSpec;
import io.onedev.server.buildspecmodel.inputspec.InputContext;
import io.onedev.server.data.migration.VersionedXmlDoc;
import io.onedev.server.service.BuildService;
import io.onedev.server.event.project.build.BuildUpdated;
import io.onedev.server.job.JobAuthorizationContext;
import io.onedev.server.job.JobAuthorizationContextAware;
import io.onedev.server.job.JobContext;
@ -56,27 +56,30 @@ import io.onedev.server.pack.PackSupport;
import io.onedev.server.search.entity.EntityQuery;
import io.onedev.server.search.entity.build.BuildQuery;
import io.onedev.server.security.SecurityUtils;
import io.onedev.server.service.BuildService;
import io.onedev.server.terminal.TerminalService;
import io.onedev.server.util.ProjectScope;
import io.onedev.server.web.WebSession;
import io.onedev.server.web.ajaxlistener.ConfirmClickListener;
import io.onedev.server.web.behavior.ChangeObserver;
import io.onedev.server.web.component.beaneditmodal.BeanEditModalPanel;
import io.onedev.server.web.component.build.side.BuildSidePanel;
import io.onedev.server.web.component.build.status.BuildStatusIcon;
import io.onedev.server.web.component.comment.CommentPanel;
import io.onedev.server.web.component.comment.ReactionSupport;
import io.onedev.server.web.component.entity.nav.EntityNavPanel;
import io.onedev.server.web.component.floating.FloatingPanel;
import io.onedev.server.web.component.job.joblist.JobListPanel;
import io.onedev.server.web.component.link.BuildSpecLink;
import io.onedev.server.web.component.link.DropdownLink;
import io.onedev.server.web.component.link.ViewStateAwarePageLink;
import io.onedev.server.web.component.markdown.ContentVersionSupport;
import io.onedev.server.web.component.markdown.MarkdownViewer;
import io.onedev.server.web.component.modal.ModalLink;
import io.onedev.server.web.component.modal.ModalPanel;
import io.onedev.server.web.component.modal.message.MessageModal;
import io.onedev.server.web.component.sideinfo.SideInfoLink;
import io.onedev.server.web.component.sideinfo.SideInfoPanel;
import io.onedev.server.web.component.tabbable.Tab;
import io.onedev.server.web.component.tabbable.Tabbable;
import io.onedev.server.web.page.base.BasePage;
import io.onedev.server.web.page.project.ProjectPage;
import io.onedev.server.web.page.project.builds.ProjectBuildsPage;
import io.onedev.server.web.page.project.builds.detail.artifacts.BuildArtifactsPage;
@ -91,13 +94,27 @@ import io.onedev.server.web.util.BuildAware;
import io.onedev.server.web.util.ConfirmClickModifier;
import io.onedev.server.web.util.Cursor;
import io.onedev.server.web.util.CursorSupport;
import io.onedev.server.web.util.DeleteCallback;
public abstract class BuildDetailPage extends ProjectPage
implements InputContext, BuildAware, JobAuthorizationContextAware {
public static final String PARAM_BUILD = "build";
@Inject
protected BuildService buildService;
@Inject
protected JobService jobService;
@Inject
protected TerminalService terminalService;
@Inject
private Set<PackSupport> packSupports;
@Inject
private Set<BuildTabContribution> buildTabContributions;
protected final IModel<Build> buildModel;
private final IModel<List<Job>> promotionsModel = new LoadableDetachableModel<List<Job>>() {
@ -137,7 +154,7 @@ public abstract class BuildDetailPage extends ProjectPage
@Override
protected Build load() {
Long buildNumber = params.get(PARAM_BUILD).toLong();
Build build = OneDev.getInstance(BuildService.class).find(getProject(), buildNumber);
Build build = buildService.find(getProject(), buildNumber);
if (build == null)
throw new EntityNotFoundException(MessageFormat.format(_T("Unable to find build #{0} in project {1}"), buildNumber, getProject()));
else if (!build.getProject().equals(getProject()))
@ -251,7 +268,7 @@ public abstract class BuildDetailPage extends ProjectPage
private void resubmit(Serializable paramBean) {
var user = SecurityUtils.getUser();
OneDev.getInstance(JobService.class).resubmit(user, getBuild(), _T("Resubmitted manually"));
jobService.resubmit(user, getBuild(), _T("Resubmitted manually"));
setResponsePage(BuildDashboardPage.class, BuildDashboardPage.paramsOf(getBuild()));
}
@ -280,7 +297,7 @@ public abstract class BuildDetailPage extends ProjectPage
@Override
public void onClick(AjaxRequestTarget target) {
OneDev.getInstance(JobService.class).cancel(getBuild());
jobService.cancel(getBuild());
getSession().success(_T("Cancel request submitted"));
}
@ -294,15 +311,11 @@ public abstract class BuildDetailPage extends ProjectPage
add(new AjaxLink<Void>("terminal") {
private TerminalService getTerminalService() {
return OneDev.getInstance(TerminalService.class);
}
@Override
public void onClick(AjaxRequestTarget target) {
if (isSubscriptionActive()) {
target.appendJavaScript(String.format("onedev.server.buildDetail.openTerminal('%s');",
getTerminalService().getTerminalUrl(getBuild())));
terminalService.getTerminalUrl(getBuild())));
} else {
new MessageModal(target) {
@ -318,7 +331,6 @@ public abstract class BuildDetailPage extends ProjectPage
protected void onConfigure() {
super.onConfigure();
JobService jobService = OneDev.getInstance(JobService.class);
JobContext jobContext = jobService.getJobContext(getBuild().getId());
setVisible(jobContext!= null && SecurityUtils.canOpenTerminal(getBuild()));
}
@ -357,6 +369,68 @@ public abstract class BuildDetailPage extends ProjectPage
}
});
add(new AjaxLink<Void>("setDescription") {
@Override
public void onClick(AjaxRequestTarget target) {
DescriptionBean bean = new DescriptionBean();
bean.setValue(getBuild().getDescription());
new BeanEditModalPanel<Serializable>(target, bean) {
@Override
protected String onSave(AjaxRequestTarget target, Serializable bean) {
getBuild().setDescription(((DescriptionBean)bean).getValue());
buildService.update(getBuild());
listenerRegistry.post(new BuildUpdated(getBuild()));
((BasePage)getPage()).notifyObservablesChange(target, getBuild().getChangeObservables());
close();
return null;
}
};
}
@Override
protected void onConfigure() {
super.onConfigure();
setVisible(SecurityUtils.canManageBuild(getBuild()) && getBuild().isFinished());
}
});
add(new ModalLink("uploadArtifacts") {
@Override
protected Component newContent(String id, ModalPanel modal) {
return new ArtifactUploadPanel(id) {
@Override
public void onUploaded(AjaxRequestTarget target) {
setResponsePage(BuildArtifactsPage.class, BuildArtifactsPage.paramsOf(getBuild()));
}
@Override
public void onCancel(AjaxRequestTarget target) {
modal.close();
}
@Override
protected Build getBuild() {
return BuildDetailPage.this.getBuild();
}
};
}
@Override
protected void onConfigure() {
super.onConfigure();
setVisible(SecurityUtils.canManageBuild(getBuild()) && getBuild().isSuccessful());
}
});
add(newBuildObserver(getBuild().getId()));
}
});
@ -406,75 +480,22 @@ public abstract class BuildDetailPage extends ProjectPage
add(jobNotFoundContainer);
add(new CommentPanel("description") {
add(new MarkdownViewer("description", new AbstractReadOnlyModel<>() {
@Override
protected String getComment() {
public String getObject() {
return getBuild().getDescription();
}
@Override
protected void onSaveComment(AjaxRequestTarget target, String comment) {
getBuild().setDescription(comment);
OneDev.getInstance(BuildService.class).update(getBuild());
}
@Override
protected Project getProject() {
return getBuild().getProject();
}
}, null) {
@Override
protected AttachmentSupport getAttachmentSupport() {
return null;
}
@Override
protected boolean canManageComment() {
return SecurityUtils.canManageBuild(getBuild());
}
@Override
protected String getRequiredLabel() {
return null;
}
@Override
protected String getEmptyDescription() {
return _T("No description");
}
@Override
protected ContentVersionSupport getContentVersionSupport() {
return null;
}
@Override
protected DeleteCallback getDeleteCallback() {
return null;
}
@Override
protected String getAutosaveKey() {
return "build:" + getBuild().getId() + ":description";
}
@Override
protected ReactionSupport getReactionSupport() {
return null;
}
@Override
protected boolean isQuoteEnabled() {
return false;
}
@Override
protected void onConfigure() {
super.onConfigure();
setVisible(getBuild().getDescription() != null || SecurityUtils.canManageBuild(getBuild()));
setVisible(getBuild().getDescription() != null);
}
});
}.setOutputMarkupPlaceholderTag(true).add(newBuildObserver(getBuild().getId())));
add(new Tabbable("buildTabs", new LoadableDetachableModel<>() {
@ -482,6 +503,10 @@ public abstract class BuildDetailPage extends ProjectPage
protected List<Tab> load() {
List<Tab> tabs = new ArrayList<>();
if (getBuild().getRootArtifacts().size() != 0) {
tabs.add(new BuildTab(Model.of(_T("Artifacts")), BuildArtifactsPage.class, BuildArtifactsPage.paramsOf(getBuild())));
}
if (SecurityUtils.canAccessLog(getBuild())) {
tabs.add(new BuildTab(Model.of(_T("Log")), BuildLogPage.class, BuildLogPage.paramsOf(getBuild())) {
@ -497,13 +522,9 @@ public abstract class BuildDetailPage extends ProjectPage
if (SecurityUtils.canAccessPipeline(getBuild()))
tabs.add(new BuildTab(Model.of(_T("Pipeline")), BuildPipelinePage.class, BuildPipelinePage.paramsOf(getBuild())));
if (SecurityUtils.canManageBuild(getBuild()) || getBuild().getRootArtifacts().size() != 0) {
tabs.add(new BuildTab(Model.of(_T("Artifacts")), BuildArtifactsPage.class, BuildArtifactsPage.paramsOf(getBuild())));
}
var packSupports = new ArrayList<>(OneDev.getExtensions(PackSupport.class));
packSupports.sort(Comparator.comparing(PackSupport::getOrder));
for (var packSupport: packSupports) {
var packSupportList = new ArrayList<>(packSupports);
packSupportList.sort(Comparator.comparing(PackSupport::getOrder));
for (var packSupport: packSupportList) {
var packType = packSupport.getPackType();
if (getBuild().getPacks().stream().anyMatch(it -> it.getType().equals(packType) && SecurityUtils.canReadPack(it.getProject()))) {
tabs.add(new BuildTab(Model.of(packSupport.getPackType()), Model.of(packSupport.getPackIcon()), BuildPacksPage.class, BuildPacksPage.paramsOf(getBuild(), packType)) {
@ -530,10 +551,10 @@ public abstract class BuildDetailPage extends ProjectPage
if (SecurityUtils.canReadCode(getProject()))
tabs.add(new BuildTab(Model.of(_T("Code Changes")), BuildChangesPage.class, BuildChangesPage.paramsOf(getBuild())));
List<BuildTabContribution> contributions = new ArrayList<>(OneDev.getExtensions(BuildTabContribution.class));
contributions.sort(Comparator.comparing(BuildTabContribution::getOrder));
List<BuildTabContribution> contributionList = new ArrayList<>(buildTabContributions);
contributionList.sort(Comparator.comparing(BuildTabContribution::getOrder));
for (BuildTabContribution contribution : contributions)
for (BuildTabContribution contribution : contributionList)
tabs.addAll(contribution.getTabs(getBuild()));
return tabs;
@ -567,7 +588,7 @@ public abstract class BuildDetailPage extends ProjectPage
@Override
public void onClick() {
OneDev.getInstance(BuildService.class).delete(getBuild());
buildService.delete(getBuild());
var oldAuditContent = VersionedXmlDoc.fromBean(getBuild()).toXML();
auditService.audit(getBuild().getProject(), "deleted build \"" + getBuild().getReference().toString(getBuild().getProject()) + "\"", oldAuditContent, null);
@ -602,7 +623,6 @@ public abstract class BuildDetailPage extends ProjectPage
@Override
protected List<Build> query(EntityQuery<Build> query, int offset, int count, ProjectScope projectScope) {
BuildService buildService = OneDev.getInstance(BuildService.class);
var subject = SecurityUtils.getSubject();
return buildService.query(subject, projectScope!=null?projectScope.getProject():null, query, false, offset, count);
}

View File

@ -0,0 +1,27 @@
package io.onedev.server.web.page.project.builds.detail;
import java.io.Serializable;
import io.onedev.server.annotation.Editable;
import io.onedev.server.annotation.Markdown;
import io.onedev.server.annotation.OmitName;
@Editable(name="Build Description")
public class DescriptionBean implements Serializable {
private static final long serialVersionUID = 1L;
private String value;
@Editable
@Markdown
@OmitName
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -1,7 +1,5 @@
<wicket:extend>
<a wicket:id="upload" class="btn btn-light btn-hover-primary btn-block mb-4"><wicket:svg href="upload" class="icon mr-2"></wicket:svg> <wicket:t>Upload</wicket:t></a>
<div wicket:id="artifacts" class="build-artifacts"></div>
<div wicket:id="noArtifacts" class="alert alert-light-warning alert-notice"><wicket:t>No artifacts published</wicket:t></div>
<wicket:fragment wicket:id="artifactFrag">
<a wicket:id="link">
<svg wicket:id="icon" class="icon"/>

View File

@ -1,23 +1,12 @@
package io.onedev.server.web.page.project.builds.detail.artifacts;
import io.onedev.server.OneDev;
import io.onedev.server.service.BuildService;
import io.onedev.server.model.Build;
import io.onedev.server.security.SecurityUtils;
import io.onedev.server.util.ChildrenAggregator;
import io.onedev.server.util.DateUtils;
import io.onedev.server.util.Pair;
import io.onedev.server.util.artifact.ArtifactInfo;
import io.onedev.server.util.artifact.DirectoryInfo;
import io.onedev.server.util.artifact.FileInfo;
import io.onedev.server.web.ajaxlistener.ConfirmClickListener;
import io.onedev.server.web.behavior.NoRecordsBehavior;
import io.onedev.server.web.component.modal.ModalLink;
import io.onedev.server.web.component.modal.ModalPanel;
import io.onedev.server.web.component.svg.SpriteImage;
import io.onedev.server.web.page.project.builds.detail.BuildDetailPage;
import io.onedev.server.web.resource.ArtifactResource;
import io.onedev.server.web.resource.ArtifactResourceReference;
import static io.onedev.server.web.translation.Translation._T;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
@ -45,12 +34,20 @@ import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import static io.onedev.server.web.translation.Translation._T;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import io.onedev.server.security.SecurityUtils;
import io.onedev.server.util.ChildrenAggregator;
import io.onedev.server.util.DateUtils;
import io.onedev.server.util.Pair;
import io.onedev.server.util.artifact.ArtifactInfo;
import io.onedev.server.util.artifact.DirectoryInfo;
import io.onedev.server.util.artifact.FileInfo;
import io.onedev.server.web.ajaxlistener.ConfirmClickListener;
import io.onedev.server.web.behavior.NoRecordsBehavior;
import io.onedev.server.web.component.svg.SpriteImage;
import io.onedev.server.web.page.project.builds.detail.BuildDetailPage;
import io.onedev.server.web.page.project.builds.detail.dashboard.BuildDashboardPage;
import io.onedev.server.web.resource.ArtifactResource;
import io.onedev.server.web.resource.ArtifactResourceReference;
public class BuildArtifactsPage extends BuildDetailPage {
@ -62,39 +59,6 @@ public class BuildArtifactsPage extends BuildDetailPage {
public void onInitialize() {
super.onInitialize();
add(new ModalLink("upload") {
@Override
protected Component newContent(String id, ModalPanel modal) {
return new ArtifactUploadPanel(id) {
@Override
public void onUploaded(AjaxRequestTarget target) {
updateArtifacts(target);
modal.close();
}
@Override
public void onCancel(AjaxRequestTarget target) {
modal.close();
}
@Override
protected Build getBuild() {
return BuildArtifactsPage.this.getBuild();
}
};
}
@Override
protected void onConfigure() {
super.onConfigure();
setVisible(SecurityUtils.canManageBuild(getBuild()));
}
});
List<IColumn<Pair<String, ArtifactInfo>, Void>> columns = new ArrayList<>();
columns.add(new TreeColumn<>(Model.of(_T("Name"))));
@ -142,8 +106,11 @@ public class BuildArtifactsPage extends BuildDetailPage {
@Override
public void onClick(AjaxRequestTarget target) {
getBuildService().deleteArtifact(getBuild(), rowModel.getObject().getRight().getPath());
updateArtifacts(target);
buildService.deleteArtifact(getBuild(), rowModel.getObject().getRight().getPath());
if (getBuild().getRootArtifacts().size() != 0)
updateArtifacts(target);
else
setResponsePage(BuildDashboardPage.class, BuildDashboardPage.paramsOf(getBuild()));
}
};
@ -164,7 +131,7 @@ public class BuildArtifactsPage extends BuildDetailPage {
if (directoryNode.getChildren() != null) {
return directoryNode.getChildren();
} else {
directoryNode = ((DirectoryInfo) getBuildService()
directoryNode = ((DirectoryInfo) buildService
.getArtifactInfo(getBuild(), directoryNode.getPath()));
return directoryNode.getChildren();
}
@ -265,24 +232,10 @@ public class BuildArtifactsPage extends BuildDetailPage {
}
});
add(new WebMarkupContainer("noArtifacts") {
@Override
protected void onConfigure() {
super.onConfigure();
setVisible(getBuild().getRootArtifacts().size() == 0);
}
}.setOutputMarkupPlaceholderTag(true));
}
private BuildService getBuildService() {
return OneDev.getInstance(BuildService.class);
}
private void updateArtifacts(AjaxRequestTarget target) {
target.add(get("artifacts"));
target.add(get("noArtifacts"));
}
@Override

View File

@ -1,21 +1,16 @@
package io.onedev.server.web.page.project.builds.detail.dashboard;
import io.onedev.server.OneDev;
import io.onedev.server.cluster.ClusterTask;
import io.onedev.server.service.BuildService;
import io.onedev.server.service.ProjectService;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.core.request.handler.PageProvider;
import org.apache.wicket.core.request.handler.RenderPageRequestHandler.RedirectPolicy;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import io.onedev.server.security.SecurityUtils;
import io.onedev.server.web.page.project.builds.detail.BuildDetailPage;
import io.onedev.server.web.page.project.builds.detail.artifacts.BuildArtifactsPage;
import io.onedev.server.web.page.project.builds.detail.issues.FixedIssuesPage;
import io.onedev.server.web.page.project.builds.detail.log.BuildLogPage;
import io.onedev.server.web.page.project.builds.detail.pipeline.BuildPipelinePage;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.core.request.handler.PageProvider;
import org.apache.wicket.core.request.handler.RenderPageRequestHandler.RedirectPolicy;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import java.io.File;
public class BuildDashboardPage extends BuildDetailPage {
@ -23,27 +18,15 @@ public class BuildDashboardPage extends BuildDetailPage {
super(params);
PageProvider pageProvider;
if (SecurityUtils.canAccessLog(getBuild())) {
if (getBuild().getRootArtifacts().size() != 0) {
pageProvider = new PageProvider(BuildArtifactsPage.class, BuildArtifactsPage.paramsOf(getBuild()));
} else if (SecurityUtils.canAccessLog(getBuild())) {
pageProvider = new PageProvider(BuildLogPage.class, BuildLogPage.paramsOf(getBuild()));
} else if (SecurityUtils.canAccessPipeline(getBuild())) {
pageProvider = new PageProvider(BuildPipelinePage.class, BuildPipelinePage.paramsOf(getBuild()));
} else {
Long projectId = getBuild().getProject().getId();
Long buildNumber = getBuild().getNumber();
boolean hasArtifacts = OneDev.getInstance(ProjectService.class).runOnActiveServer(projectId, new ClusterTask<Boolean>() {
@Override
public Boolean call() throws Exception {
File artifactsDir = OneDev.getInstance(BuildService.class).getArtifactsDir(projectId, buildNumber);
return artifactsDir.exists() && artifactsDir.listFiles().length != 0;
}
});
if (hasArtifacts)
pageProvider = new PageProvider(BuildArtifactsPage.class, BuildArtifactsPage.paramsOf(getBuild()));
else
pageProvider = new PageProvider(FixedIssuesPage.class, FixedIssuesPage.paramsOf(getBuild()));
pageProvider = new PageProvider(FixedIssuesPage.class, FixedIssuesPage.paramsOf(getBuild()));
}
throw new RestartResponseException(pageProvider, RedirectPolicy.NEVER_REDIRECT);

View File

@ -1886,10 +1886,11 @@ public class Translation_de extends TranslationResourceBundle {
m.put("Low Severity", "Niedrige Schwere");
m.put("MERGED", "VERMISCHT");
m.put("MS Teams Notifications", "MS Teams-Benachrichtigungen");
m.put("Mail", "Mail");
m.put("Mail Connector", "Mail-Connector");
m.put("Mail Connector Bean", "Mail-Connector-Bean");
m.put("Mail Service", "Mail-Dienst");
m.put("Mail Service Bean", "Mail-Dienst-Bean");
m.put("Mail Service Test", "Mail-Dienst-Test");
m.put("Mail service", "Mail-Dienst");
m.put("Mail service not configured", "Mail-Dienst nicht konfiguriert");
m.put("Mail service settings saved", "Mail-Dienst-Einstellungen gespeichert");
m.put("Make sure <a href=\"https://openjdk.java.net\" target=\"_blank\">Java 11 or higher</a> is installed",
@ -2065,7 +2066,6 @@ public class Translation_de extends TranslationResourceBundle {
m.put("No any", "Kein Einziger");
m.put("No any matches", "Keine Übereinstimmungen");
m.put("No applicable transitions or no permission to transit", "Keine anwendbaren Übergänge oder keine Berechtigung zum Übergang");
m.put("No artifacts published", "Keine Artefakte veröffentlicht");
m.put("No attributes defined (can only be edited when agent is online)", "Keine Attribute definiert (können nur bearbeitet werden, wenn der Agent online ist)");
m.put("No audits", "Keine Audits");
m.put("No authorized job secret found (project: {0}, job secret: {1})", "Kein autorisiertes Job-Geheimnis gefunden (Projekt: {0}, Job-Geheimnis: {1})");
@ -3191,6 +3191,7 @@ public class Translation_de extends TranslationResourceBundle {
m.put("Set Up Your Account", "Richten Sie Ihr Konto ein");
m.put("Set as Private", "Als privat festlegen");
m.put("Set as Public", "Als öffentlich festlegen");
m.put("Set description", "Beschreibung festlegen");
m.put("Set reviewed", "Als überprüft markieren");
m.put("Set unreviewed", "Als nicht überprüft markieren");
m.put("Set up Microsoft Teams notification settings. Settings will be inherited by child projects, and can be overridden by defining settings with same webhook url. ",
@ -4129,6 +4130,7 @@ public class Translation_de extends TranslationResourceBundle {
m.put("Upload Strategy", "Upload-Strategie");
m.put("Upload a 128x128 transparent png file to be used as logo for dark mode", "Laden Sie eine 128x128 transparente PNG-Datei hoch, die als Logo für den Dunkelmodus verwendet werden soll");
m.put("Upload a 128x128 transparent png file to be used as logo for light mode", "Laden Sie eine 128x128 transparente PNG-Datei hoch, die als Logo für den Hellmodus verwendet werden soll");
m.put("Upload artifacts", "Artefakte hochladen");
m.put("Upload avatar", "Avatar hochladen");
m.put("Upload should be less than {0} Mb", "Upload sollte weniger als {0} MB betragen");
m.put("Upload to Project", "Zum Projekt hochladen");

View File

@ -1886,10 +1886,11 @@ public class Translation_es extends TranslationResourceBundle {
m.put("Low Severity", "Severidad Baja");
m.put("MERGED", "FUSIONADO");
m.put("MS Teams Notifications", "Notificaciones de MS Teams");
m.put("Mail", "Correo");
m.put("Mail Connector", "Conector de Correo");
m.put("Mail Connector Bean", "Bean de Conector de Correo");
m.put("Mail Service", "Servicio de Correo");
m.put("Mail Service Bean", "Bean del Servicio de Correo");
m.put("Mail Service Test", "Prueba del Servicio de Correo");
m.put("Mail service", "Servicio de correo");
m.put("Mail service not configured", "Servicio de correo no configurado");
m.put("Mail service settings saved", "Configuraciones del servicio de correo guardadas");
m.put("Make sure <a href=\"https://openjdk.java.net\" target=\"_blank\">Java 11 or higher</a> is installed",
@ -2065,7 +2066,6 @@ public class Translation_es extends TranslationResourceBundle {
m.put("No any", "No hay ninguno");
m.put("No any matches", "No hay coincidencias");
m.put("No applicable transitions or no permission to transit", "No hay transiciones aplicables o no hay permiso para transitar");
m.put("No artifacts published", "No se publicaron artefactos");
m.put("No attributes defined (can only be edited when agent is online)", "No hay atributos definidos (solo se pueden editar cuando el agente está en línea)");
m.put("No audits", "Sin auditorías");
m.put("No authorized job secret found (project: {0}, job secret: {1})", "No se encontró un secreto de trabajo autorizado (proyecto: {0}, secreto de trabajo: {1})");
@ -3191,6 +3191,7 @@ public class Translation_es extends TranslationResourceBundle {
m.put("Set Up Your Account", "Configure su cuenta");
m.put("Set as Private", "Establecer como privado");
m.put("Set as Public", "Establecer como público");
m.put("Set description", "Establecer descripción");
m.put("Set reviewed", "Marcar como revisado");
m.put("Set unreviewed", "Marcar como no revisado");
m.put("Set up Microsoft Teams notification settings. Settings will be inherited by child projects, and can be overridden by defining settings with same webhook url. ",
@ -4129,6 +4130,7 @@ public class Translation_es extends TranslationResourceBundle {
m.put("Upload Strategy", "Estrategia de subida");
m.put("Upload a 128x128 transparent png file to be used as logo for dark mode", "Subir un archivo PNG transparente de 128x128 para usar como logo en modo oscuro");
m.put("Upload a 128x128 transparent png file to be used as logo for light mode", "Subir un archivo PNG transparente de 128x128 para usar como logo en modo claro");
m.put("Upload artifacts", "Subir artefactos");
m.put("Upload avatar", "Subir avatar");
m.put("Upload should be less than {0} Mb", "La subida debe ser menor a {0} Mb");
m.put("Upload to Project", "Subir al proyecto");

View File

@ -1886,10 +1886,11 @@ public class Translation_fr extends TranslationResourceBundle {
m.put("Low Severity", "Gravité Faible");
m.put("MERGED", "FUSIONNÉ");
m.put("MS Teams Notifications", "Notifications MS Teams");
m.put("Mail", "Mail");
m.put("Mail Connector", "Connecteur de Mail");
m.put("Mail Connector Bean", "Bean de Connecteur de Mail");
m.put("Mail Service", "Service de Messagerie");
m.put("Mail Service Bean", "Bean du Service de Messagerie");
m.put("Mail Service Test", "Test du Service de Messagerie");
m.put("Mail service", "Service de messagerie");
m.put("Mail service not configured", "Service de messagerie non configuré");
m.put("Mail service settings saved", "Paramètres du service de messagerie enregistrés");
m.put("Make sure <a href=\"https://openjdk.java.net\" target=\"_blank\">Java 11 or higher</a> is installed",
@ -2065,7 +2066,6 @@ public class Translation_fr extends TranslationResourceBundle {
m.put("No any", "Aucun");
m.put("No any matches", "Aucune correspondance");
m.put("No applicable transitions or no permission to transit", "Aucune transition applicable ou aucune permission pour effectuer la transition");
m.put("No artifacts published", "Aucun artefact publié");
m.put("No attributes defined (can only be edited when agent is online)", "Aucun attribut défini (peut être modifié uniquement lorsque l'agent est en ligne)");
m.put("No audits", "Aucun audit");
m.put("No authorized job secret found (project: {0}, job secret: {1})", "Aucun secret de tâche autorisé trouvé (projet : {0}, secret de tâche : {1})");
@ -3191,6 +3191,7 @@ public class Translation_fr extends TranslationResourceBundle {
m.put("Set Up Your Account", "Configurez votre compte");
m.put("Set as Private", "Définir comme privé");
m.put("Set as Public", "Définir comme public");
m.put("Set description", "Définir la description");
m.put("Set reviewed", "Marquer comme examiné");
m.put("Set unreviewed", "Marquer comme non examiné");
m.put("Set up Microsoft Teams notification settings. Settings will be inherited by child projects, and can be overridden by defining settings with same webhook url. ",
@ -4129,6 +4130,7 @@ public class Translation_fr extends TranslationResourceBundle {
m.put("Upload Strategy", "Stratégie de téléversement");
m.put("Upload a 128x128 transparent png file to be used as logo for dark mode", "Téléverser un fichier PNG transparent 128x128 à utiliser comme logo pour le mode sombre");
m.put("Upload a 128x128 transparent png file to be used as logo for light mode", "Téléverser un fichier PNG transparent 128x128 à utiliser comme logo pour le mode clair");
m.put("Upload artifacts", "Télécharger les artefacts");
m.put("Upload avatar", "Téléverser un avatar");
m.put("Upload should be less than {0} Mb", "Le téléversement doit être inférieur à {0} Mo");
m.put("Upload to Project", "Téléverser vers le projet");

View File

@ -1886,10 +1886,11 @@ public class Translation_it extends TranslationResourceBundle {
m.put("Low Severity", "Gravità Bassa");
m.put("MERGED", "UNITO");
m.put("MS Teams Notifications", "Notifiche MS Teams");
m.put("Mail", "Mail");
m.put("Mail Connector", "Connettore Mail");
m.put("Mail Connector Bean", "Bean Connettore Mail");
m.put("Mail Service", "Servizio di Posta");
m.put("Mail Service Bean", "Bean del Servizio di Posta");
m.put("Mail Service Test", "Test del Servizio di Posta");
m.put("Mail service", "Servizio di posta");
m.put("Mail service not configured", "Servizio di posta non configurato");
m.put("Mail service settings saved", "Impostazioni del servizio di posta salvate");
m.put("Make sure <a href=\"https://openjdk.java.net\" target=\"_blank\">Java 11 or higher</a> is installed",
@ -2065,7 +2066,6 @@ public class Translation_it extends TranslationResourceBundle {
m.put("No any", "Nessuno");
m.put("No any matches", "Nessuna corrispondenza");
m.put("No applicable transitions or no permission to transit", "Nessuna transizione applicabile o nessun permesso per transitare");
m.put("No artifacts published", "Nessun artefatto pubblicato");
m.put("No attributes defined (can only be edited when agent is online)", "Nessun attributo definito (modificabile solo quando l'agente è online)");
m.put("No audits", "Nessun controllo");
m.put("No authorized job secret found (project: {0}, job secret: {1})", "Nessun segreto autorizzato trovato (progetto: {0}, segreto: {1})");
@ -3191,6 +3191,7 @@ public class Translation_it extends TranslationResourceBundle {
m.put("Set Up Your Account", "Configura il Tuo Account");
m.put("Set as Private", "Imposta come privato");
m.put("Set as Public", "Imposta come pubblico");
m.put("Set description", "Imposta descrizione");
m.put("Set reviewed", "Imposta come revisionato");
m.put("Set unreviewed", "Imposta come non revisionato");
m.put("Set up Microsoft Teams notification settings. Settings will be inherited by child projects, and can be overridden by defining settings with same webhook url. ",
@ -4129,6 +4130,7 @@ public class Translation_it extends TranslationResourceBundle {
m.put("Upload Strategy", "Strategia di caricamento");
m.put("Upload a 128x128 transparent png file to be used as logo for dark mode", "Carica un file PNG trasparente 128x128 da utilizzare come logo per la modalità scura");
m.put("Upload a 128x128 transparent png file to be used as logo for light mode", "Carica un file PNG trasparente 128x128 da utilizzare come logo per la modalità chiara");
m.put("Upload artifacts", "Carica artefatti");
m.put("Upload avatar", "Carica avatar");
m.put("Upload should be less than {0} Mb", "Il caricamento deve essere inferiore a {0} Mb");
m.put("Upload to Project", "Carica nel progetto");

View File

@ -1886,10 +1886,11 @@ public class Translation_ja extends TranslationResourceBundle {
m.put("Low Severity", "低い重大度");
m.put("MERGED", "マージ済み");
m.put("MS Teams Notifications", "MS Teams通知");
m.put("Mail", "メール");
m.put("Mail Connector", "メールコネクタ");
m.put("Mail Connector Bean", "メールコネクタビーン");
m.put("Mail Service", "メールサービス");
m.put("Mail Service Bean", "メールサービスBean");
m.put("Mail Service Test", "メールサービステスト");
m.put("Mail service", "メールサービス");
m.put("Mail service not configured", "メールサービスが構成されていません");
m.put("Mail service settings saved", "メールサービス設定が保存されました");
m.put("Make sure <a href=\"https://openjdk.java.net\" target=\"_blank\">Java 11 or higher</a> is installed",
@ -2065,7 +2066,6 @@ public class Translation_ja extends TranslationResourceBundle {
m.put("No any", "何もなし");
m.put("No any matches", "一致するものがありません");
m.put("No applicable transitions or no permission to transit", "適用可能な遷移がないか、遷移する権限がありません");
m.put("No artifacts published", "公開されたアーティファクトなし");
m.put("No attributes defined (can only be edited when agent is online)", "定義された属性なし(エージェントがオンラインの場合のみ編集可能)");
m.put("No audits", "監査なし");
m.put("No authorized job secret found (project: {0}, job secret: {1})", "認証済みのジョブシークレットが見つかりません(プロジェクト: {0}, ジョブシークレット: {1}");
@ -3191,6 +3191,7 @@ public class Translation_ja extends TranslationResourceBundle {
m.put("Set Up Your Account", "アカウントを設定する");
m.put("Set as Private", "非公開として設定");
m.put("Set as Public", "公開として設定");
m.put("Set description", "説明を設定");
m.put("Set reviewed", "レビュー済みとして設定");
m.put("Set unreviewed", "未レビューとして設定");
m.put("Set up Microsoft Teams notification settings. Settings will be inherited by child projects, and can be overridden by defining settings with same webhook url. ",
@ -4129,6 +4130,7 @@ public class Translation_ja extends TranslationResourceBundle {
m.put("Upload Strategy", "アップロード戦略");
m.put("Upload a 128x128 transparent png file to be used as logo for dark mode", "ダークモード用のロゴとして使用する128x128の透明なPNGファイルをアップロード");
m.put("Upload a 128x128 transparent png file to be used as logo for light mode", "ライトモード用のロゴとして使用する128x128の透明なPNGファイルをアップロード");
m.put("Upload artifacts", "アーティファクトをアップロード");
m.put("Upload avatar", "アバターをアップロード");
m.put("Upload should be less than {0} Mb", "アップロードは{0}MB未満である必要があります");
m.put("Upload to Project", "プロジェクトにアップロード");

View File

@ -1886,10 +1886,11 @@ public class Translation_ko extends TranslationResourceBundle {
m.put("Low Severity", "낮은 심각도");
m.put("MERGED", "병합됨");
m.put("MS Teams Notifications", "MS Teams 알림");
m.put("Mail", "메일");
m.put("Mail Connector", "메일 커넥터");
m.put("Mail Connector Bean", "메일 커넥터 빈");
m.put("Mail Service", "메일 서비스");
m.put("Mail Service Bean", "메일 서비스 빈");
m.put("Mail Service Test", "메일 서비스 테스트");
m.put("Mail service", "메일 서비스");
m.put("Mail service not configured", "메일 서비스가 구성되지 않음");
m.put("Mail service settings saved", "메일 서비스 설정이 저장됨");
m.put("Make sure <a href=\"https://openjdk.java.net\" target=\"_blank\">Java 11 or higher</a> is installed",
@ -2065,7 +2066,6 @@ public class Translation_ko extends TranslationResourceBundle {
m.put("No any", "없음");
m.put("No any matches", "일치하는 항목이 없습니다");
m.put("No applicable transitions or no permission to transit", "적용 가능한 전환 없음 또는 전환 권한 없음");
m.put("No artifacts published", "게시된 아티팩트 없음");
m.put("No attributes defined (can only be edited when agent is online)", "정의된 속성 없음 (에이전트가 온라인 상태일 때만 편집 가능)");
m.put("No audits", "감사 없음");
m.put("No authorized job secret found (project: {0}, job secret: {1})", "승인된 작업 비밀 없음 (프로젝트: {0}, 작업 비밀: {1})");
@ -3191,6 +3191,7 @@ public class Translation_ko extends TranslationResourceBundle {
m.put("Set Up Your Account", "계정을 설정하세요");
m.put("Set as Private", "비공개로 설정");
m.put("Set as Public", "공개로 설정");
m.put("Set description", "설명 설정");
m.put("Set reviewed", "검토됨으로 설정");
m.put("Set unreviewed", "미검토로 설정");
m.put("Set up Microsoft Teams notification settings. Settings will be inherited by child projects, and can be overridden by defining settings with same webhook url. ",
@ -4129,6 +4130,7 @@ public class Translation_ko extends TranslationResourceBundle {
m.put("Upload Strategy", "업로드 전략");
m.put("Upload a 128x128 transparent png file to be used as logo for dark mode", "다크 모드 로고로 사용하기 위해 128x128 투명 png 파일 업로드");
m.put("Upload a 128x128 transparent png file to be used as logo for light mode", "라이트 모드 로고로 사용하기 위해 128x128 투명 png 파일 업로드");
m.put("Upload artifacts", "아티팩트 업로드");
m.put("Upload avatar", "아바타 업로드");
m.put("Upload should be less than {0} Mb", "업로드는 {0} Mb보다 작아야 합니다");
m.put("Upload to Project", "프로젝트로 업로드");

View File

@ -1886,10 +1886,11 @@ public class Translation_pt extends TranslationResourceBundle {
m.put("Low Severity", "Baixa Severidade");
m.put("MERGED", "FUNDIDO");
m.put("MS Teams Notifications", "Notificações do MS Teams");
m.put("Mail", "Correio");
m.put("Mail Connector", "Conector de Correio");
m.put("Mail Connector Bean", "Bean do Conector de Correio");
m.put("Mail Service", "Serviço de Email");
m.put("Mail Service Bean", "Bean do Serviço de Email");
m.put("Mail Service Test", "Teste do Serviço de Email");
m.put("Mail service", "Serviço de email");
m.put("Mail service not configured", "Serviço de email não configurado");
m.put("Mail service settings saved", "Configurações do serviço de email salvas");
m.put("Make sure <a href=\"https://openjdk.java.net\" target=\"_blank\">Java 11 or higher</a> is installed",
@ -2065,7 +2066,6 @@ public class Translation_pt extends TranslationResourceBundle {
m.put("No any", "Nenhum");
m.put("No any matches", "Nenhuma correspondência");
m.put("No applicable transitions or no permission to transit", "Sem transições aplicáveis ou sem permissão para transitar");
m.put("No artifacts published", "Sem artefatos publicados");
m.put("No attributes defined (can only be edited when agent is online)", "Sem atributos definidos (só podem ser editados quando o agente está online)");
m.put("No audits", "Sem auditorias");
m.put("No authorized job secret found (project: {0}, job secret: {1})", "Nenhum segredo de trabalho autorizado encontrado (projeto: {0}, segredo de trabalho: {1})");
@ -3191,6 +3191,7 @@ public class Translation_pt extends TranslationResourceBundle {
m.put("Set Up Your Account", "Configure Sua Conta");
m.put("Set as Private", "Definir como Privado");
m.put("Set as Public", "Definir como Público");
m.put("Set description", "Definir descrição");
m.put("Set reviewed", "Definir como Revisado");
m.put("Set unreviewed", "Definir como Não Revisado");
m.put("Set up Microsoft Teams notification settings. Settings will be inherited by child projects, and can be overridden by defining settings with same webhook url. ",
@ -4129,6 +4130,7 @@ public class Translation_pt extends TranslationResourceBundle {
m.put("Upload Strategy", "Estratégia de Envio");
m.put("Upload a 128x128 transparent png file to be used as logo for dark mode", "Envie um arquivo PNG transparente 128x128 para ser usado como logotipo no modo escuro");
m.put("Upload a 128x128 transparent png file to be used as logo for light mode", "Envie um arquivo PNG transparente 128x128 para ser usado como logotipo no modo claro");
m.put("Upload artifacts", "Carregar artefatos");
m.put("Upload avatar", "Enviar avatar");
m.put("Upload should be less than {0} Mb", "O envio deve ser menor que {0} Mb");
m.put("Upload to Project", "Enviar para o Projeto");

View File

@ -30,7 +30,8 @@ public class Translation_zh extends TranslationResourceBundle {
"'two factor authentication' should be translated to '两阶段验证'\n" +
"Space should be added between English words and Chinese words\n" +
"'SSO provider' should be translated as SSO 提供方\n" +
"'post build' should be translated as 构建后")
"'post build' should be translated as 构建后\n" +
"'artifact' should be translated as 制品")
public static void init(Map<String, String> m) {
m.clear();
m.put(" Project path can be omitted if reference from current project", "如果从当前项目引用,则可以省略项目路径");
@ -1902,10 +1903,11 @@ public class Translation_zh extends TranslationResourceBundle {
m.put("Low Severity", "轻微");
m.put("MERGED", "已合并");
m.put("MS Teams Notifications", "MS Teams 通知");
m.put("Mail", "邮件");
m.put("Mail Connector", "邮件连接器");
m.put("Mail Connector Bean", "邮件连接器 Bean");
m.put("Mail Service", "邮件服务");
m.put("Mail Service Bean", "邮件服务Bean");
m.put("Mail Service Test", "邮件服务测试");
m.put("Mail service", "邮件服务");
m.put("Mail service not configured", "邮件服务未配置");
m.put("Mail service settings saved", "邮件服务设置已保存");
m.put("Make sure <a href=\"https://openjdk.java.net\" target=\"_blank\">Java 11 or higher</a> is installed",
@ -2081,7 +2083,6 @@ public class Translation_zh extends TranslationResourceBundle {
m.put("No any", "无任何");
m.put("No any matches", "没有任何匹配项");
m.put("No applicable transitions or no permission to transit", "没有适用的转换或没有权限转换");
m.put("No artifacts published", "没有发布制品");
m.put("No attributes defined (can only be edited when agent is online)", "没有定义属性(仅当代理在线时可编辑)");
m.put("No audits", "无审计记录");
m.put("No authorized job secret found (project: {0}, job secret: {1})", "未找到授权的任务密钥(项目:{0},任务密钥:{1}");
@ -3207,6 +3208,7 @@ public class Translation_zh extends TranslationResourceBundle {
m.put("Set Up Your Account", "设置您的账户");
m.put("Set as Private", "设为私有");
m.put("Set as Public", "设为公开");
m.put("Set description", "设置描述");
m.put("Set reviewed", "设置为已审阅");
m.put("Set unreviewed", "设置为未审阅");
m.put("Set up Microsoft Teams notification settings. Settings will be inherited by child projects, and can be overridden by defining settings with same webhook url. ",
@ -4621,6 +4623,7 @@ public class Translation_zh extends TranslationResourceBundle {
m.put("{javax.validation.constraints.NotEmpty.message}", "不能为空");
m.put("{javax.validation.constraints.NotNull.message}", "不能为空");
m.put("{javax.validation.constraints.Size.message}", "至少需要指定一个值");
m.put("Upload artifacts", "上传制品");
}
@Override

View File

@ -0,0 +1,160 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.wicket.guice;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.core.util.lang.WicketObjects;
import org.apache.wicket.proxy.IProxyTargetLocator;
import org.apache.wicket.util.lang.Objects;
import com.google.inject.ConfigurationException;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import io.onedev.commons.loader.AppLoader;
class GuiceProxyTargetLocator implements IProxyTargetLocator
{
private static final long serialVersionUID = 1L;
private final Annotation bindingAnnotation;
private final boolean optional;
private final String className;
private final String fieldName;
private Boolean isSingletonCache = null;
public GuiceProxyTargetLocator(final Field field, final Annotation bindingAnnotation,
final boolean optional)
{
this.bindingAnnotation = bindingAnnotation;
this.optional = optional;
className = field.getDeclaringClass().getName();
fieldName = field.getName();
}
@Override
public Object locateProxyTarget()
{
Injector injector = getInjector();
final Key<?> key = newGuiceKey();
// if the Inject annotation is marked optional and no binding is found
// then skip this injection (WICKET-2241)
if (optional)
{
// Guice 2.0 throws a ConfigurationException if no binding is find while 1.0 simply
// returns null.
try
{
if (injector.getBinding(key) == null)
{
return null;
}
}
catch (RuntimeException e)
{
return null;
}
}
return injector.getInstance(key);
}
private Key<?> newGuiceKey()
{
final Type type;
try
{
Class<?> clazz = WicketObjects.resolveClass(className);
final Field field = clazz.getDeclaredField(fieldName);
type = field.getGenericType();
}
catch (Exception e)
{
throw new WicketRuntimeException("Error accessing member: " + fieldName +
" of class: " + className, e);
}
// using TypeLiteral to retrieve the key gives us automatic support for
// Providers and other injectable TypeLiterals
if (bindingAnnotation == null)
{
return Key.get(TypeLiteral.get(type));
}
else
{
return Key.get(TypeLiteral.get(type), bindingAnnotation);
}
}
public boolean isSingletonScope()
{
if (isSingletonCache == null)
{
try
{
isSingletonCache = Scopes.isSingleton(getInjector().getBinding(newGuiceKey()));
}
catch (ConfigurationException ex)
{
// No binding, if optional can pretend this is null singleton
if (optional)
isSingletonCache = true;
else
throw ex;
}
}
return isSingletonCache;
}
private Injector getInjector()
{
return AppLoader.injector;
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (!(o instanceof GuiceProxyTargetLocator))
return false;
GuiceProxyTargetLocator that = (GuiceProxyTargetLocator) o;
return Objects.equal(optional, that.optional) &&
Objects.equal(bindingAnnotation, that.bindingAnnotation) &&
Objects.equal(className, that.className) &&
Objects.equal(fieldName, that.fieldName);
}
@Override
public int hashCode()
{
return Objects.hashCode(bindingAnnotation, optional, className, fieldName);
}
}